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.
- data/LICENSE +20 -0
- data/README.md +82 -0
- data/lib/krypt.rb +49 -0
- data/lib/krypt/asn1.rb +3 -0
- data/lib/krypt/asn1/common.rb +96 -0
- data/lib/krypt/asn1/template.rb +257 -0
- data/lib/krypt/codec.rb +57 -0
- data/lib/krypt/codec/base64.rb +140 -0
- data/lib/krypt/codec/base_codec.rb +36 -0
- data/lib/krypt/codec/hex.rb +122 -0
- data/lib/krypt/digest.rb +112 -0
- data/lib/krypt/hmac.rb +69 -0
- data/lib/krypt/pkcs5.rb +1 -0
- data/lib/krypt/pkcs5/pbkdf2.rb +41 -0
- data/lib/krypt/provider.rb +35 -0
- data/lib/krypt/x509.rb +3 -0
- data/lib/krypt/x509/certificate.rb +36 -0
- data/lib/krypt/x509/common.rb +41 -0
- data/lib/krypt/x509/crl.rb +33 -0
- data/lib/krypt_missing.rb +32 -0
- data/spec/krypt-core/MEMO.txt +85 -0
- data/spec/krypt-core/asn1/asn1_bit_string_spec.rb +475 -0
- data/spec/krypt-core/asn1/asn1_boolean_spec.rb +392 -0
- data/spec/krypt-core/asn1/asn1_constants_spec.rb +71 -0
- data/spec/krypt-core/asn1/asn1_data_spec.rb +1153 -0
- data/spec/krypt-core/asn1/asn1_end_of_contents_spec.rb +133 -0
- data/spec/krypt-core/asn1/asn1_enumerated_spec.rb +458 -0
- data/spec/krypt-core/asn1/asn1_generalized_time_spec.rb +492 -0
- data/spec/krypt-core/asn1/asn1_integer_spec.rb +557 -0
- data/spec/krypt-core/asn1/asn1_null_spec.rb +360 -0
- data/spec/krypt-core/asn1/asn1_object_id_spec.rb +495 -0
- data/spec/krypt-core/asn1/asn1_octet_string_spec.rb +456 -0
- data/spec/krypt-core/asn1/asn1_parser_spec.rb +503 -0
- data/spec/krypt-core/asn1/asn1_pem_spec.rb +282 -0
- data/spec/krypt-core/asn1/asn1_sequence_spec.rb +637 -0
- data/spec/krypt-core/asn1/asn1_set_spec.rb +795 -0
- data/spec/krypt-core/asn1/asn1_utc_time_spec.rb +495 -0
- data/spec/krypt-core/asn1/asn1_utf8_string_spec.rb +404 -0
- data/spec/krypt-core/asn1/resources.rb +53 -0
- data/spec/krypt-core/base64/base64_spec.rb +97 -0
- data/spec/krypt-core/digest/digest_spec.rb +707 -0
- data/spec/krypt-core/hex/hex_spec.rb +102 -0
- data/spec/krypt-core/pem/pem_decode_spec.rb +235 -0
- data/spec/krypt-core/resources.rb +1 -0
- data/spec/krypt-core/template/template_choice_parse_spec.rb +289 -0
- data/spec/krypt-core/template/template_dsl_spec.rb +351 -0
- data/spec/krypt-core/template/template_seq_of_parse_spec.rb +64 -0
- data/spec/krypt-core/template/template_seq_parse_spec.rb +1241 -0
- data/spec/krypt/codec/base64_decoder_spec.rb +94 -0
- data/spec/krypt/codec/base64_encoder_spec.rb +94 -0
- data/spec/krypt/codec/base64_mixed_spec.rb +16 -0
- data/spec/krypt/codec/hex_decoder_spec.rb +94 -0
- data/spec/krypt/codec/hex_encoder_spec.rb +94 -0
- data/spec/krypt/codec/hex_mixed_spec.rb +17 -0
- data/spec/krypt/codec/identity_shared.rb +119 -0
- data/spec/krypt/hmac/hmac_spec.rb +311 -0
- data/spec/krypt/pkcs5/pbkdf2_spec.rb +79 -0
- data/spec/krypt/provider/provider_spec.rb +83 -0
- data/spec/res/ca-bundle.crt +11758 -0
- data/spec/res/certificate.cer +0 -0
- data/spec/res/certificate.pem +20 -0
- data/spec/res/multiple_certs.pem +60 -0
- data/spec/resources.rb +66 -0
- data/test/helper.rb +8 -0
- data/test/res/certificate.cer +0 -0
- data/test/resources.rb +48 -0
- data/test/scratch.rb +28 -0
- data/test/test_krypt_asn1.rb +119 -0
- data/test/test_krypt_parser.rb +331 -0
- metadata +134 -0
@@ -0,0 +1,503 @@
|
|
1
|
+
# encoding: US-ASCII
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'krypt'
|
5
|
+
require_relative '../resources'
|
6
|
+
require 'stringio'
|
7
|
+
|
8
|
+
def do_and_close(io)
|
9
|
+
yield io
|
10
|
+
io.close
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Krypt::ASN1::Parser do
|
14
|
+
|
15
|
+
it "can be instantiated with default constructor" do
|
16
|
+
Krypt::ASN1::Parser.new.should be_an_instance_of Krypt::ASN1::Parser
|
17
|
+
end
|
18
|
+
|
19
|
+
it "takes no arguments in its constructor" do
|
20
|
+
lambda { Krypt::ASN1::Parser.new(Object.new) }.should raise_error(ArgumentError)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should be reusable for several IOs" do
|
24
|
+
parser = Krypt::ASN1::Parser.new
|
25
|
+
io = Resources.certificate_io
|
26
|
+
do_and_close(io) { |io| parser.next(io).should_not be_nil }
|
27
|
+
io = Resources.certificate_io
|
28
|
+
do_and_close(io) { |io| parser.next(io).should_not be_nil }
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe Krypt::ASN1::Parser, "#next" do
|
34
|
+
|
35
|
+
subject { Krypt::ASN1::Parser.new }
|
36
|
+
|
37
|
+
it "returns a Header when called on an IO representing an ASN.1" do
|
38
|
+
io = Resources.certificate_io
|
39
|
+
do_and_close(io) { |io| parse_next io }
|
40
|
+
parse_next(StringIO.new(Resources.certificate))
|
41
|
+
end
|
42
|
+
|
43
|
+
it "raises an ArgumentError when called on a String. A String does not
|
44
|
+
provide internal state that would be needed for parsing." do
|
45
|
+
lambda { parse_next(Resources.certificate) }.should raise_error(ArgumentError)
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_next(io)
|
49
|
+
subject.next(io).should be_an_instance_of Krypt::ASN1::Header
|
50
|
+
end
|
51
|
+
|
52
|
+
it "raises ArgumentError if anything other than an IO is passed. Rejection
|
53
|
+
is handled depending on the presence of a #read method." do
|
54
|
+
lambda { subject.next(:sym) }.should raise_error(ArgumentError)
|
55
|
+
|
56
|
+
c = Class.new do
|
57
|
+
def initialize
|
58
|
+
@io = Resources.certificate_io
|
59
|
+
end
|
60
|
+
|
61
|
+
def read(len=nil, buf=nil)
|
62
|
+
@io.read(len, buf)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
parse_next(c.new)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "does not close the underlying IO after reading it" do
|
70
|
+
io = Resources.certificate_io
|
71
|
+
subject.next(io).skip_value
|
72
|
+
subject.next(io).should be_nil
|
73
|
+
io.closed?.should be_false
|
74
|
+
io.close
|
75
|
+
io.closed?.should be_true
|
76
|
+
end
|
77
|
+
|
78
|
+
it "reads nested Headers when called subsequently for constructed values" do
|
79
|
+
num_headers = 0
|
80
|
+
io = Resources.certificate_io
|
81
|
+
while header = subject.next(io)
|
82
|
+
num_headers += 1
|
83
|
+
next if header.constructed?
|
84
|
+
header.skip_value #need to consume the values
|
85
|
+
end
|
86
|
+
num_headers.should > 1
|
87
|
+
io.close
|
88
|
+
end
|
89
|
+
|
90
|
+
it "also reads singular, non-constructed values" do
|
91
|
+
io = Resources.bytes_to_io( %w{02 01 01} )
|
92
|
+
header = subject.next(io)
|
93
|
+
header.tag.should == 2
|
94
|
+
header.size.should == 1
|
95
|
+
header.header_size.should == 2
|
96
|
+
header.tag_class.should == :UNIVERSAL
|
97
|
+
header.constructed?.should be_false
|
98
|
+
header.infinite?.should be_false
|
99
|
+
header.value.should == "\x01"
|
100
|
+
end
|
101
|
+
|
102
|
+
it "yields the original contents for the header and the value of the
|
103
|
+
initial sequence" do
|
104
|
+
cert = Resources.certificate
|
105
|
+
io = StringIO.new cert
|
106
|
+
header = subject.next io
|
107
|
+
value = header.value
|
108
|
+
(header.header_size + value.size).should == cert.size
|
109
|
+
("" << header.bytes << value).should == cert
|
110
|
+
end
|
111
|
+
|
112
|
+
it "yields the original contents for the nested headers and their values" do
|
113
|
+
cert = Resources.certificate
|
114
|
+
io = StringIO.new cert
|
115
|
+
out = ""
|
116
|
+
while header = subject.next(io)
|
117
|
+
out << header.bytes
|
118
|
+
next if header.constructed?
|
119
|
+
val = header.value
|
120
|
+
out << val unless val == nil
|
121
|
+
end
|
122
|
+
out.should == cert
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
describe Krypt::ASN1::Header do
|
128
|
+
|
129
|
+
it "cannot be instantiated" do
|
130
|
+
lambda { Krypt::ASN1::Header.new }.should raise_error
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
describe Krypt::ASN1::Header, "#tag" do
|
136
|
+
|
137
|
+
subject { Krypt::ASN1::Parser.new }
|
138
|
+
|
139
|
+
it "yields the tag of an ASN1 value, both for simple and complex tags" do
|
140
|
+
simple = Resources.bytes_to_io( %w{05 00} )
|
141
|
+
header = subject.next(simple)
|
142
|
+
header.tag.should == 5
|
143
|
+
end
|
144
|
+
|
145
|
+
it "yields the tag for complex tags with a single octet" do
|
146
|
+
complex_single_octet = %w{df 2a 01}
|
147
|
+
complex_single_octet_v = Resources.bytes_to_io(Array.new(complex_single_octet) << '00')
|
148
|
+
header = subject.next(complex_single_octet_v)
|
149
|
+
header.tag.should == 42
|
150
|
+
end
|
151
|
+
|
152
|
+
it "yields the tag for complext tags with multiple octets" do
|
153
|
+
complex_two_octets = %w{5f 82 2c 01}
|
154
|
+
complex_two_octets_v = Resources.bytes_to_io(Array.new(complex_two_octets) << '00')
|
155
|
+
header = subject.next(complex_two_octets_v)
|
156
|
+
header.tag.should == 300
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
describe Krypt::ASN1::Header, "#tag_class" do
|
162
|
+
|
163
|
+
it "recognizes UNIVERSAL, CONTEXT_SPEICIFIC, APPLICATION and PRIVATE" do
|
164
|
+
subject = Krypt::ASN1::Parser.new
|
165
|
+
universal = Resources.bytes_to_io( %w{05 00} )
|
166
|
+
header = subject.next(universal)
|
167
|
+
header.tag_class.should == :UNIVERSAL
|
168
|
+
context_specific = Resources.bytes_to_io( %w{81 00} )
|
169
|
+
header = subject.next(context_specific)
|
170
|
+
header.tag_class.should == :CONTEXT_SPECIFIC
|
171
|
+
private_tc = Resources.bytes_to_io( %w{df 2a 01} )
|
172
|
+
header = subject.next(private_tc)
|
173
|
+
header.tag_class.should == :PRIVATE
|
174
|
+
application = Resources.bytes_to_io( %w{5f 82 2c 01} )
|
175
|
+
header = subject.next(application)
|
176
|
+
header.tag_class.should == :APPLICATION
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
describe Krypt::ASN1::Header, "#constructed?" do
|
182
|
+
|
183
|
+
subject { Krypt::ASN1::Parser.new }
|
184
|
+
|
185
|
+
it "returns false for primitive values" do
|
186
|
+
evaluate(%w{05 00}, false)
|
187
|
+
evaluate(%w{81 00}, false)
|
188
|
+
evaluate(%w{df 2a 01}, false)
|
189
|
+
evaluate(%w{5f 82 2c 01}, false)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "returns true for constructed values" do
|
193
|
+
evaluate(%w{30 03 02 01 01}, true)
|
194
|
+
evaluate(%w{31 03 02 01 01}, true)
|
195
|
+
evaluate(%w{30 80 02 01 01 00 00}, true)
|
196
|
+
evaluate(%w{24 80 04 01 01 00 00}, true)
|
197
|
+
end
|
198
|
+
|
199
|
+
def evaluate(bytes, expectation)
|
200
|
+
io = Resources.bytes_to_io bytes
|
201
|
+
header = subject.next io
|
202
|
+
header.constructed?.should == expectation
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
describe Krypt::ASN1::Header, "#infinite?" do
|
208
|
+
|
209
|
+
subject { Krypt::ASN1::Parser.new }
|
210
|
+
|
211
|
+
it "returns false for definite length values" do
|
212
|
+
evaluate(%w{05 00}, false)
|
213
|
+
evaluate(%w{81 00}, false)
|
214
|
+
evaluate(%w{df 2a 01}, false)
|
215
|
+
evaluate(%w{5f 82 2c 01}, false)
|
216
|
+
evaluate(%w{30 03 02 01 01}, false)
|
217
|
+
evaluate(%w{31 03 02 01 01}, false)
|
218
|
+
end
|
219
|
+
|
220
|
+
it "returns true for infinite length values" do
|
221
|
+
evaluate(%w{30 80 02 01 01 00 00}, true)
|
222
|
+
evaluate(%w{31 80 02 01 01 00 00}, true)
|
223
|
+
evaluate(%w{24 80 04 01 01 00 00}, true)
|
224
|
+
end
|
225
|
+
|
226
|
+
it "raises an error for infinite length primitive values" do
|
227
|
+
lambda { evaluate(%w{04 80 04 01 01 00 00}, true) }.should raise_error(Krypt::ASN1::ParseError)
|
228
|
+
end
|
229
|
+
|
230
|
+
def evaluate(bytes, expectation)
|
231
|
+
io = Resources.bytes_to_io bytes
|
232
|
+
header = subject.next io
|
233
|
+
header.infinite?.should == expectation
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
describe Krypt::ASN1::Header, "#size" do
|
239
|
+
|
240
|
+
subject { Krypt::ASN1::Parser.new }
|
241
|
+
|
242
|
+
it "returns the size of the value for single octet lengths" do
|
243
|
+
simple = Resources.bytes_to_io( %w{02 01 01} )
|
244
|
+
header = subject.next(simple)
|
245
|
+
header.size.should == 1
|
246
|
+
end
|
247
|
+
|
248
|
+
it "returns the size of the value for multiple octet lengths" do
|
249
|
+
complex = Resources.bytes_to_io( %w{04 82 03 e8} << ('a' * 1000))
|
250
|
+
header = subject.next complex
|
251
|
+
header.size.should == 1000
|
252
|
+
end
|
253
|
+
|
254
|
+
it "returns 0 for missing values" do
|
255
|
+
null = %w{05 00}
|
256
|
+
eoc = %w{00 00}
|
257
|
+
subject.next(Resources.bytes_to_io(null)).size.should == 0
|
258
|
+
subject.next(Resources.bytes_to_io(eoc)).size.should == 0
|
259
|
+
end
|
260
|
+
|
261
|
+
it "returns 0 for infinite length values" do
|
262
|
+
inf = %w{30 80 02 01 01 00 00}
|
263
|
+
subject.next(Resources.bytes_to_io(inf)).size.should == 0
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
describe Krypt::ASN1::Header, "#header_size" do
|
269
|
+
|
270
|
+
subject { Krypt::ASN1::Parser.new }
|
271
|
+
|
272
|
+
it "returns the size of the sum of tag plus length encoding
|
273
|
+
for simple tags" do
|
274
|
+
simple = Resources.bytes_to_io( %w{05 00} )
|
275
|
+
header = subject.next(simple)
|
276
|
+
header.header_size.should == 2
|
277
|
+
end
|
278
|
+
|
279
|
+
it "returns the size of the sum of tag plus length encoding
|
280
|
+
for complex tags with a single octet" do
|
281
|
+
complex_single_octet = %w{df 2a 01}
|
282
|
+
complex_single_octet_v = Resources.bytes_to_io(Array.new(complex_single_octet) << '00')
|
283
|
+
header = subject.next(complex_single_octet_v)
|
284
|
+
header.header_size.should == 3
|
285
|
+
end
|
286
|
+
|
287
|
+
it "returns the size of the sum of tag plus length encoding
|
288
|
+
for complex tags with multiple octets" do
|
289
|
+
complex_two_octets = %w{5f 82 2c 01}
|
290
|
+
complex_two_octets_v = Resources.bytes_to_io(Array.new(complex_two_octets) << '00')
|
291
|
+
header = subject.next(complex_two_octets_v)
|
292
|
+
header.header_size.should == 4
|
293
|
+
end
|
294
|
+
|
295
|
+
it "returns the size of the header for multiple octet lengths" do
|
296
|
+
complex = Resources.bytes_to_io( %w{04 82 03 e8} << ('a' * 1000))
|
297
|
+
header = subject.next complex
|
298
|
+
header.header_size.should == 4
|
299
|
+
end
|
300
|
+
|
301
|
+
end
|
302
|
+
|
303
|
+
describe Krypt::ASN1::Header, "#skip_value" do
|
304
|
+
|
305
|
+
it "skips to the end of the file when asked to skip the value of a
|
306
|
+
starting constructed value" do
|
307
|
+
skip_value(StringIO.new(Resources.certificate))
|
308
|
+
skip_value Resources.certificate_io
|
309
|
+
end
|
310
|
+
|
311
|
+
def skip_value(io)
|
312
|
+
parser = Krypt::ASN1::Parser.new
|
313
|
+
header = parser.next(io)
|
314
|
+
header.skip_value
|
315
|
+
parser.next(io).should be_nil
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
319
|
+
|
320
|
+
describe Krypt::ASN1::Header, "#value" do
|
321
|
+
|
322
|
+
subject { Krypt::ASN1::Parser.new }
|
323
|
+
|
324
|
+
it "caches the value of a header once it was read" do
|
325
|
+
io = Resources.certificate_io
|
326
|
+
begin
|
327
|
+
header = subject.next(io)
|
328
|
+
header.value.should == header.value
|
329
|
+
ensure
|
330
|
+
io.close
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
it "returns nil for missing values" do
|
335
|
+
null = %w{05 00}
|
336
|
+
eoc = %w{00 00}
|
337
|
+
subject.next(Resources.bytes_to_io(null)).value.should be_nil
|
338
|
+
subject.next(Resources.bytes_to_io(eoc)).value.should be_nil
|
339
|
+
end
|
340
|
+
|
341
|
+
it "has Encoding::BINARY" do
|
342
|
+
io = Resources.certificate_io
|
343
|
+
begin
|
344
|
+
subject.next(io).value.encoding.should == Encoding::BINARY
|
345
|
+
ensure
|
346
|
+
io.close
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
end
|
351
|
+
|
352
|
+
describe Krypt::ASN1::Header, "#value_io" do
|
353
|
+
|
354
|
+
subject { Krypt::ASN1::Parser.new }
|
355
|
+
|
356
|
+
it "returns an IO that reads the entire value of a definite sequence" do
|
357
|
+
cert = Resources.certificate_io
|
358
|
+
header = subject.next cert
|
359
|
+
(header.bytes << header.value_io.read).should == Resources.certificate
|
360
|
+
cert.close
|
361
|
+
end
|
362
|
+
|
363
|
+
it "returns an IO whose content is in Encoding::BINARY" do
|
364
|
+
cert = Resources.certificate_io
|
365
|
+
header = subject.next cert
|
366
|
+
header.value_io.read.encoding.should == Encoding::BINARY
|
367
|
+
cert.close
|
368
|
+
end
|
369
|
+
|
370
|
+
it "reads the values excluding the headers for an infinite length primitive
|
371
|
+
value by default" do
|
372
|
+
io = Resources.bytes_to_io( %w{24 80 04 01 01 04 01 02 00 00} )
|
373
|
+
expected = [%w{01 02}.join('')].pack('H*')
|
374
|
+
header = subject.next io
|
375
|
+
header.value_io.read.should == expected
|
376
|
+
end
|
377
|
+
|
378
|
+
it "reads the values including the headers for an infinite length primitive
|
379
|
+
value when passed false as a parameter" do
|
380
|
+
io = Resources.bytes_to_io( %w{24 80 04 01 01 04 01 02 00 00} )
|
381
|
+
expected = [%w{04 01 01 04 01 02 00 00}.join('')].pack('H*')
|
382
|
+
header = subject.next io
|
383
|
+
header.value_io(false).read.should == expected
|
384
|
+
end
|
385
|
+
|
386
|
+
it "reads the values excluding the headers for an infinite length sequence
|
387
|
+
by default" do
|
388
|
+
io = Resources.bytes_to_io( %w{30 80 04 01 01 04 01 02 00 00} )
|
389
|
+
expected = [%w{01 02}.join('')].pack('H*')
|
390
|
+
header = subject.next io
|
391
|
+
header.value_io.read.should == expected
|
392
|
+
end
|
393
|
+
|
394
|
+
it "reads the values including the headers for an infinite length sequence
|
395
|
+
when passed false as a parameter" do
|
396
|
+
io = Resources.bytes_to_io( %w{30 80 04 01 01 04 01 02 00 00} )
|
397
|
+
expected = [%w{04 01 01 04 01 02 00 00}.join('')].pack('H*')
|
398
|
+
header = subject.next io
|
399
|
+
header.value_io(false).read.should == expected
|
400
|
+
end
|
401
|
+
|
402
|
+
it "caches an IO if requested for a header more than once" do
|
403
|
+
io = Resources.certificate_io
|
404
|
+
header = subject.next io
|
405
|
+
header.value_io
|
406
|
+
lambda { header.value_io }.should_not raise_error
|
407
|
+
io.close
|
408
|
+
end
|
409
|
+
|
410
|
+
it "raises an error if the value of a header is requested after requesting
|
411
|
+
an IO" do
|
412
|
+
io = Resources.certificate_io
|
413
|
+
header = subject.next io
|
414
|
+
header.value_io
|
415
|
+
lambda { header.value }.should raise_error(Krypt::ASN1::ParseError)
|
416
|
+
io.close
|
417
|
+
end
|
418
|
+
|
419
|
+
it "raises an error if an IO after reading the value of the header" do
|
420
|
+
io = Resources.certificate_io
|
421
|
+
header = subject.next io
|
422
|
+
header.value
|
423
|
+
lambda { header.value_io }.should raise_error(Krypt::ASN1::ParseError)
|
424
|
+
io.close
|
425
|
+
end
|
426
|
+
|
427
|
+
it "is stateful wrt to the amount of data already read" do
|
428
|
+
io = Resources.certificate_io
|
429
|
+
header = subject.next io
|
430
|
+
header.value_io.read.should_not == ""
|
431
|
+
header.value_io.read.should == ""
|
432
|
+
io.close
|
433
|
+
end
|
434
|
+
|
435
|
+
it "returns an 'empty' IO for missing values" do
|
436
|
+
null = %w{05 00}
|
437
|
+
eoc = %w{00 00}
|
438
|
+
subject.next(Resources.bytes_to_io(null)).value_io.read.should == ""
|
439
|
+
subject.next(Resources.bytes_to_io(eoc)).value_io.read.should == ""
|
440
|
+
end
|
441
|
+
|
442
|
+
end
|
443
|
+
|
444
|
+
describe Krypt::ASN1::Header, "#bytes" do
|
445
|
+
|
446
|
+
subject { Krypt::ASN1::Parser.new }
|
447
|
+
|
448
|
+
it "returns the encoding of a parsed header" do
|
449
|
+
complex_two_octets = %w{5f 82 2c 01}
|
450
|
+
complex_two_octets_v = Resources.bytes_to_io(Array.new(complex_two_octets) << '00')
|
451
|
+
header = subject.next(complex_two_octets_v)
|
452
|
+
header.bytes.should == Resources.bytes(complex_two_octets)
|
453
|
+
end
|
454
|
+
|
455
|
+
it "returns the encoding of a simple tag" do
|
456
|
+
raw = %w{05 00}
|
457
|
+
simple = Resources.bytes_to_io(raw)
|
458
|
+
header = subject.next(simple)
|
459
|
+
header.bytes.should == Resources.bytes(raw)
|
460
|
+
end
|
461
|
+
|
462
|
+
it "returns the encoding for complex tags with a single octet" do
|
463
|
+
complex_single_octet = %w{df 2a 01}
|
464
|
+
complex_single_octet_v = Resources.bytes_to_io(Array.new(complex_single_octet) << '00')
|
465
|
+
header = subject.next(complex_single_octet_v)
|
466
|
+
header.bytes.should == Resources.bytes(complex_single_octet)
|
467
|
+
end
|
468
|
+
|
469
|
+
it "returns the encoding for complex tags with multiple octets" do
|
470
|
+
complex_two_octets = %w{5f 82 2c 01}
|
471
|
+
complex_two_octets_v = Resources.bytes_to_io(Array.new(complex_two_octets) << '00')
|
472
|
+
header = subject.next(complex_two_octets_v)
|
473
|
+
header.bytes.should == Resources.bytes(complex_two_octets)
|
474
|
+
end
|
475
|
+
|
476
|
+
it "returns the encoding for multiple octet lengths" do
|
477
|
+
raw = %w{04 82 03 e8}
|
478
|
+
complex = Resources.bytes_to_io( Array.new(raw) << ('a' * 1000))
|
479
|
+
header = subject.next complex
|
480
|
+
header.bytes.should == Resources.bytes(raw)
|
481
|
+
end
|
482
|
+
|
483
|
+
it "has Encoding::BINARY" do
|
484
|
+
raw = %w{05 00}
|
485
|
+
io = Resources.bytes_to_io(raw)
|
486
|
+
subject.next(io).bytes.encoding.should == Encoding::BINARY
|
487
|
+
end
|
488
|
+
|
489
|
+
end
|
490
|
+
|
491
|
+
describe Krypt::ASN1::Header, "#encode_to" do
|
492
|
+
|
493
|
+
it "encodes the header to an IO" do
|
494
|
+
null = %w{05 00}
|
495
|
+
io = Resources.bytes_to_io(null)
|
496
|
+
header = Krypt::ASN1::Parser.new.next io
|
497
|
+
out = StringIO.new
|
498
|
+
header.encode_to(out)
|
499
|
+
out.string.should == header.bytes
|
500
|
+
end
|
501
|
+
|
502
|
+
end
|
503
|
+
|