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,795 @@
|
|
1
|
+
# encoding: US-ASCII
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'krypt'
|
5
|
+
require 'openssl'
|
6
|
+
require_relative './resources'
|
7
|
+
|
8
|
+
describe Krypt::ASN1::Set do
|
9
|
+
include Krypt::ASN1::Resources
|
10
|
+
|
11
|
+
let(:mod) { Krypt::ASN1 }
|
12
|
+
let(:klass) { mod::Set }
|
13
|
+
let(:decoder) { mod }
|
14
|
+
let(:asn1error) { mod::ASN1Error }
|
15
|
+
|
16
|
+
# For test against OpenSSL
|
17
|
+
#
|
18
|
+
#let(:mod) { OpenSSL::ASN1 }
|
19
|
+
#
|
20
|
+
# OpenSSL stub for signature mismatch
|
21
|
+
class OpenSSL::ASN1::Set
|
22
|
+
class << self
|
23
|
+
alias old_new new
|
24
|
+
def new(*args)
|
25
|
+
if args.size > 1
|
26
|
+
args = [args[0], args[1], :IMPLICIT, args[2]]
|
27
|
+
end
|
28
|
+
old_new(*args)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#new' do
|
34
|
+
context 'gets value for construct' do
|
35
|
+
subject { klass.new(value) }
|
36
|
+
|
37
|
+
context 'accepts SET as Array' do
|
38
|
+
let(:value) { [s('hello'), i(42), s('world')] }
|
39
|
+
its(:tag) { should == Krypt::ASN1::SET }
|
40
|
+
its(:tag_class) { should == :UNIVERSAL }
|
41
|
+
its(:value) { should == value }
|
42
|
+
its(:infinite_length) { should == false }
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'accepts SET OF as Array' do
|
46
|
+
let(:value) { [s('hello'), s(','), s('world')] }
|
47
|
+
its(:tag) { should == Krypt::ASN1::SET }
|
48
|
+
its(:tag_class) { should == :UNIVERSAL }
|
49
|
+
its(:value) { should == value }
|
50
|
+
its(:infinite_length) { should == false }
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'accepts empty Array' do
|
54
|
+
let(:value) { [] }
|
55
|
+
its(:value) { should == [] }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'gets explicit tag number as the 2nd argument' do
|
60
|
+
let(:value) { [s('hello')] }
|
61
|
+
subject { klass.new(value, tag, :PRIVATE) }
|
62
|
+
|
63
|
+
context 'accepts default tag' do
|
64
|
+
let(:tag) { Krypt::ASN1::SET }
|
65
|
+
its(:tag) { should == tag }
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'accepts custom tag' do
|
69
|
+
let(:tag) { 14 }
|
70
|
+
its(:tag) { should == tag }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'gets tag class symbol as the 3rd argument' do
|
75
|
+
let(:value) { [s('hello')] }
|
76
|
+
subject { klass.new(value, Krypt::ASN1::SET, tag_class) }
|
77
|
+
|
78
|
+
context 'accepts :UNIVERSAL' do
|
79
|
+
let(:tag_class) { :UNIVERSAL }
|
80
|
+
its(:tag_class) { should == tag_class }
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'accepts :APPLICATION' do
|
84
|
+
let(:tag_class) { :APPLICATION }
|
85
|
+
its(:tag_class) { should == tag_class }
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'accepts :CONTEXT_SPECIFIC' do
|
89
|
+
let(:tag_class) { :CONTEXT_SPECIFIC }
|
90
|
+
its(:tag_class) { should == tag_class }
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'accepts :PRIVATE' do
|
94
|
+
let(:tag_class) { :PRIVATE }
|
95
|
+
its(:tag_class) { should == tag_class }
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'accepts :IMPLICIT' do
|
99
|
+
let(:tag_class) { :IMPLICIT }
|
100
|
+
its(:tag_class) { should == tag_class }
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'accepts :EXPLICIT' do
|
104
|
+
let(:tag_class) { :EXPLICIT }
|
105
|
+
its(:tag_class) { should == tag_class }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'when the 2nd argument is given but 3rd argument is omitted' do
|
110
|
+
subject { klass.new([s('hello')], Krypt::ASN1::SET) }
|
111
|
+
its(:tag_class) { should == :CONTEXT_SPECIFIC }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe 'accessors' do
|
116
|
+
describe '#value' do
|
117
|
+
subject { o = klass.new(nil); o.value = value; o }
|
118
|
+
|
119
|
+
context 'accepts SET as Array' do
|
120
|
+
let(:value) { [s('hello'), i(42), s('world')] }
|
121
|
+
its(:tag) { should == Krypt::ASN1::SET }
|
122
|
+
its(:tag_class) { should == :UNIVERSAL }
|
123
|
+
its(:value) { should == value }
|
124
|
+
its(:infinite_length) { should == false }
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'accepts SET OF as Array' do
|
128
|
+
let(:value) { [s('hello'), s(','), s('world')] }
|
129
|
+
its(:tag) { should == Krypt::ASN1::SET }
|
130
|
+
its(:tag_class) { should == :UNIVERSAL }
|
131
|
+
its(:value) { should == value }
|
132
|
+
its(:infinite_length) { should == false }
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'accepts empty Array' do
|
136
|
+
let(:value) { [] }
|
137
|
+
its(:value) { should == [] }
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#tag' do
|
142
|
+
subject { o = klass.new(nil); o.tag = tag; o }
|
143
|
+
|
144
|
+
context 'accepts default tag' do
|
145
|
+
let(:tag) { Krypt::ASN1::SET }
|
146
|
+
its(:tag) { should == tag }
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'accepts custom tag' do
|
150
|
+
let(:tag) { 14 }
|
151
|
+
its(:tag) { should == tag }
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe '#tag_class' do
|
156
|
+
subject { o = klass.new(nil); o.tag_class = tag_class; o }
|
157
|
+
|
158
|
+
context 'accepts :UNIVERSAL' do
|
159
|
+
let(:tag_class) { :UNIVERSAL }
|
160
|
+
its(:tag_class) { should == tag_class }
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'accepts :APPLICATION' do
|
164
|
+
let(:tag_class) { :APPLICATION }
|
165
|
+
its(:tag_class) { should == tag_class }
|
166
|
+
end
|
167
|
+
|
168
|
+
context 'accepts :CONTEXT_SPECIFIC' do
|
169
|
+
let(:tag_class) { :CONTEXT_SPECIFIC }
|
170
|
+
its(:tag_class) { should == tag_class }
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'accepts :PRIVATE' do
|
174
|
+
let(:tag_class) { :PRIVATE }
|
175
|
+
its(:tag_class) { should == tag_class }
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'accepts :IMPLICIT' do
|
179
|
+
let(:tag_class) { :IMPLICIT }
|
180
|
+
its(:tag_class) { should == tag_class }
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'accepts :EXPLICIT' do
|
184
|
+
let(:tag_class) { :EXPLICIT }
|
185
|
+
its(:tag_class) { should == tag_class }
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe '#infinite_length' do
|
190
|
+
subject { o = klass.new(nil); o.infinite_length = infinite_length; o }
|
191
|
+
|
192
|
+
context 'accepts true' do
|
193
|
+
let(:infinite_length) { true }
|
194
|
+
its(:infinite_length) { should == true }
|
195
|
+
end
|
196
|
+
|
197
|
+
context 'accepts false' do
|
198
|
+
let(:infinite_length) { false }
|
199
|
+
its(:infinite_length) { should == false }
|
200
|
+
end
|
201
|
+
|
202
|
+
context 'accepts nil as false' do
|
203
|
+
let(:infinite_length) { nil }
|
204
|
+
its(:infinite_length) { should == false }
|
205
|
+
end
|
206
|
+
|
207
|
+
context 'accepts non boolean as true' do
|
208
|
+
let(:infinite_length) { Object.new }
|
209
|
+
its(:infinite_length) { should == true }
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe '#to_der' do
|
215
|
+
context 'encodes a given value' do
|
216
|
+
subject { klass.new(value).to_der }
|
217
|
+
|
218
|
+
context 'SET' do
|
219
|
+
let(:value) { [s('hello'), i(42), s('world')] }
|
220
|
+
it { should == "\x31\x11\x02\x01\x2A\x04\x05hello\x04\x05world" }
|
221
|
+
end
|
222
|
+
|
223
|
+
context 'SET OF OctetString' do
|
224
|
+
let(:value) { [s(''), s(''), s('')] }
|
225
|
+
it { should == "\x31\x06\x04\x00\x04\x00\x04\x00" }
|
226
|
+
end
|
227
|
+
|
228
|
+
context 'SET OF Integer' do
|
229
|
+
let(:value) { [i(-1), i(0), i(1)] }
|
230
|
+
it { should == "\x31\x09\x02\x01\x00\x02\x01\x01\x02\x01\xFF" }
|
231
|
+
end
|
232
|
+
|
233
|
+
context '(empty)' do
|
234
|
+
let(:value) { [] }
|
235
|
+
it { should == "\x31\x00" }
|
236
|
+
end
|
237
|
+
|
238
|
+
context '1000 elements' do
|
239
|
+
let(:value) { [i(0)] * 1000 }
|
240
|
+
it { should == "\x31\x82\x0B\xB8" + "\x02\x01\x00" * 1000 }
|
241
|
+
end
|
242
|
+
|
243
|
+
context 'responds to :each and to sort' do
|
244
|
+
let(:value) {
|
245
|
+
o = Object.new
|
246
|
+
def o.each
|
247
|
+
yield Krypt::ASN1::OctetString.new('hello')
|
248
|
+
yield Krypt::ASN1::Integer.new(42)
|
249
|
+
yield Krypt::ASN1::OctetString.new('world')
|
250
|
+
end
|
251
|
+
def o.sort
|
252
|
+
[
|
253
|
+
Krypt::ASN1::OctetString.new('hello'),
|
254
|
+
Krypt::ASN1::Integer.new(42),
|
255
|
+
Krypt::ASN1::OctetString.new('world')
|
256
|
+
].sort
|
257
|
+
end
|
258
|
+
o
|
259
|
+
}
|
260
|
+
it { should == "\x31\x11\x02\x01\x2A\x04\x05hello\x04\x05world" }
|
261
|
+
end
|
262
|
+
|
263
|
+
context 'responds to :each, but not sortable' do
|
264
|
+
let(:value) {
|
265
|
+
o = Object.new
|
266
|
+
def o.each
|
267
|
+
yield Krypt::ASN1::OctetString.new('hello')
|
268
|
+
yield Krypt::ASN1::Integer.new(42)
|
269
|
+
yield Krypt::ASN1::OctetString.new('world')
|
270
|
+
end
|
271
|
+
o
|
272
|
+
}
|
273
|
+
it { should == "\x31\x11\x02\x01\x2A\x04\x05hello\x04\x05world" }
|
274
|
+
end
|
275
|
+
|
276
|
+
context "orders SET encoding by tag when creating the SET" do
|
277
|
+
context "definite length Array" do
|
278
|
+
let (:value) { [
|
279
|
+
Krypt::ASN1::Null.new,
|
280
|
+
Krypt::ASN1::Integer.new(1),
|
281
|
+
Krypt::ASN1::Boolean.new(true)
|
282
|
+
] }
|
283
|
+
it { should == "\x31\x08\x01\x01\xFF\x02\x01\x01\x05\x00" }
|
284
|
+
end
|
285
|
+
|
286
|
+
context "definite length Enumerable" do
|
287
|
+
let(:value) {
|
288
|
+
o = Object.new
|
289
|
+
def o.each
|
290
|
+
yield Krypt::ASN1::Null.new
|
291
|
+
yield Krypt::ASN1::Integer.new(1)
|
292
|
+
yield Krypt::ASN1::Boolean.new(true)
|
293
|
+
end
|
294
|
+
o
|
295
|
+
}
|
296
|
+
it { should == "\x31\x08\x01\x01\xFF\x02\x01\x01\x05\x00" }
|
297
|
+
end
|
298
|
+
|
299
|
+
context "infinite length" do
|
300
|
+
subject { o = klass.new(value); o.infinite_length = true; o.to_der }
|
301
|
+
|
302
|
+
context "infinite length Array" do
|
303
|
+
let (:value) { [
|
304
|
+
Krypt::ASN1::Null.new,
|
305
|
+
Krypt::ASN1::Integer.new(1),
|
306
|
+
Krypt::ASN1::Boolean.new(true)
|
307
|
+
] }
|
308
|
+
it { should == "\x31\x80\x01\x01\xFF\x02\x01\x01\x05\x00\x00\x00" }
|
309
|
+
end
|
310
|
+
|
311
|
+
context "infinite length Enumerable" do
|
312
|
+
let(:value) {
|
313
|
+
o = Object.new
|
314
|
+
def o.each
|
315
|
+
yield Krypt::ASN1::Null.new
|
316
|
+
yield Krypt::ASN1::Integer.new(1)
|
317
|
+
yield Krypt::ASN1::Boolean.new(true)
|
318
|
+
end
|
319
|
+
o
|
320
|
+
}
|
321
|
+
it { should == "\x31\x80\x01\x01\xFF\x02\x01\x01\x05\x00\x00\x00" }
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
context "orders SET OF encoding in lexicographical order when creating the SET" do
|
327
|
+
context "definite length Array" do
|
328
|
+
let (:value) { [
|
329
|
+
Krypt::ASN1::OctetString.new("aaaaaa"),
|
330
|
+
Krypt::ASN1::OctetString.new("aaaab"),
|
331
|
+
Krypt::ASN1::OctetString.new("aaa"),
|
332
|
+
Krypt::ASN1::OctetString.new("b")
|
333
|
+
] }
|
334
|
+
it { should == "\x31\x17\x04\x01b\x04\x03aaa\x04\x05aaaab\x04\x06aaaaaa" }
|
335
|
+
end
|
336
|
+
|
337
|
+
context "definite length Enumerable" do
|
338
|
+
let (:value) {
|
339
|
+
o = Object.new
|
340
|
+
def o.each
|
341
|
+
yield Krypt::ASN1::OctetString.new("aaaaaa")
|
342
|
+
yield Krypt::ASN1::OctetString.new("aaaab")
|
343
|
+
yield Krypt::ASN1::OctetString.new("aaa")
|
344
|
+
yield Krypt::ASN1::OctetString.new("b")
|
345
|
+
end
|
346
|
+
o
|
347
|
+
}
|
348
|
+
it { should == "\x31\x17\x04\x01b\x04\x03aaa\x04\x05aaaab\x04\x06aaaaaa" }
|
349
|
+
end
|
350
|
+
|
351
|
+
context "infinite length" do
|
352
|
+
subject { o = klass.new(value); o.infinite_length = true; o.to_der }
|
353
|
+
|
354
|
+
context "Array" do
|
355
|
+
let (:value) { [
|
356
|
+
Krypt::ASN1::OctetString.new("aaaaaa"),
|
357
|
+
Krypt::ASN1::OctetString.new("aaaab"),
|
358
|
+
Krypt::ASN1::OctetString.new("aaa"),
|
359
|
+
Krypt::ASN1::OctetString.new("b")
|
360
|
+
] }
|
361
|
+
it { should == "\x31\x80\x04\x01b\x04\x03aaa\x04\x05aaaab\x04\x06aaaaaa\x00\x00" }
|
362
|
+
end
|
363
|
+
|
364
|
+
context "Enumerable" do
|
365
|
+
let (:value) {
|
366
|
+
o = Object.new
|
367
|
+
def o.each
|
368
|
+
yield Krypt::ASN1::OctetString.new("aaaaaa")
|
369
|
+
yield Krypt::ASN1::OctetString.new("aaaab")
|
370
|
+
yield Krypt::ASN1::OctetString.new("aaa")
|
371
|
+
yield Krypt::ASN1::OctetString.new("b")
|
372
|
+
end
|
373
|
+
o
|
374
|
+
}
|
375
|
+
it { should == "\x31\x80\x04\x01b\x04\x03aaa\x04\x05aaaab\x04\x06aaaaaa\x00\x00" }
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
context 'nil' do
|
381
|
+
let(:value) { nil }
|
382
|
+
it { -> { subject }.should raise_error asn1error }
|
383
|
+
end
|
384
|
+
|
385
|
+
context 'does not respond to :each' do
|
386
|
+
let(:value) { '123' }
|
387
|
+
it { -> { subject }.should raise_error asn1error }
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
context 'encodes tag number' do
|
392
|
+
let(:value) { [s(''), s(''), s('')] }
|
393
|
+
subject { klass.new(value, tag, :PRIVATE).to_der }
|
394
|
+
|
395
|
+
context 'default tag' do
|
396
|
+
let(:tag) { Krypt::ASN1::SET }
|
397
|
+
it { should == "\xF1\x06\x04\x00\x04\x00\x04\x00" }
|
398
|
+
end
|
399
|
+
|
400
|
+
context 'custom tag' do
|
401
|
+
let(:tag) { 14 }
|
402
|
+
it { should == "\xEE\x06\x04\x00\x04\x00\x04\x00" }
|
403
|
+
end
|
404
|
+
|
405
|
+
context 'nil' do
|
406
|
+
let(:tag) { nil }
|
407
|
+
it { -> { subject }.should raise_error asn1error }
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
context 'encodes tag class' do
|
412
|
+
let(:value) { [s(''), s(''), s('')] }
|
413
|
+
subject { klass.new(value, Krypt::ASN1::SET, tag_class).to_der }
|
414
|
+
|
415
|
+
context 'UNIVERSAL' do
|
416
|
+
let(:tag_class) { :UNIVERSAL }
|
417
|
+
it { should == "\x31\x06\x04\x00\x04\x00\x04\x00" }
|
418
|
+
end
|
419
|
+
|
420
|
+
context 'APPLICATION' do
|
421
|
+
let(:tag_class) { :APPLICATION }
|
422
|
+
it { should == "\x71\x06\x04\x00\x04\x00\x04\x00" }
|
423
|
+
end
|
424
|
+
|
425
|
+
context 'CONTEXT_SPECIFIC' do
|
426
|
+
let(:tag_class) { :CONTEXT_SPECIFIC }
|
427
|
+
it { should == "\xB1\x06\x04\x00\x04\x00\x04\x00" }
|
428
|
+
end
|
429
|
+
|
430
|
+
context 'PRIVATE' do
|
431
|
+
let(:tag_class) { :PRIVATE }
|
432
|
+
it { should == "\xF1\x06\x04\x00\x04\x00\x04\x00" }
|
433
|
+
end
|
434
|
+
|
435
|
+
context 'IMPLICIT' do
|
436
|
+
let(:tag_class) { :IMPLICIT }
|
437
|
+
it { should == "\xB1\x06\x04\x00\x04\x00\x04\x00" }
|
438
|
+
end
|
439
|
+
|
440
|
+
context 'EXPLICIT' do
|
441
|
+
let(:tag_class) { :EXPLICIT }
|
442
|
+
it { should == "\xB1\x08\x31\x06\x04\x00\x04\x00\x04\x00" }
|
443
|
+
end
|
444
|
+
|
445
|
+
context nil do
|
446
|
+
let(:tag_class) { nil }
|
447
|
+
it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check nil
|
448
|
+
end
|
449
|
+
|
450
|
+
context :no_such_class do
|
451
|
+
let(:tag_class) { :no_such_class }
|
452
|
+
it { -> { subject }.should raise_error asn1error }
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
context 'encodes indefinite length packets' do
|
457
|
+
subject {
|
458
|
+
o = klass.new(nil, Krypt::ASN1::SET, :UNIVERSAL)
|
459
|
+
o.value = value if defined? value
|
460
|
+
o.infinite_length = true
|
461
|
+
o
|
462
|
+
}
|
463
|
+
|
464
|
+
context 'with EndOfContents' do
|
465
|
+
let(:value) { [s('hello'), i(42), s('world'), eoc] }
|
466
|
+
let(:infinite_length) { true }
|
467
|
+
its(:to_der) { should == "\x31\x80\x02\x01\x2A\x04\x05hello\x04\x05world\x00\x00" }
|
468
|
+
end
|
469
|
+
|
470
|
+
context 'with 0-tagged zero-length value without EndOfContents' do
|
471
|
+
let(:value) { [i(0), i(-1), Krypt::ASN1::ASN1Data.new(nil, 0, :CONTEXT_SPECIFIC)] }
|
472
|
+
let(:infinite_length) { true }
|
473
|
+
its(:to_der) { should == "\x31\x80\x80\x00\x02\x01\x00\x02\x01\xFF\x00\x00" }
|
474
|
+
end
|
475
|
+
|
476
|
+
context 'with 0-tagged zero-length value with EndOfContents' do
|
477
|
+
let(:value) { [i(0), i(-1), Krypt::ASN1::ASN1Data.new(nil, 0, :CONTEXT_SPECIFIC), Krypt::ASN1::EndOfContents.new] }
|
478
|
+
let(:infinite_length) { true }
|
479
|
+
its(:to_der) { should == "\x31\x80\x80\x00\x02\x01\x00\x02\x01\xFF\x00\x00" }
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
context 'encodes values set via accessors' do
|
484
|
+
subject {
|
485
|
+
o = klass.new(nil)
|
486
|
+
o.value = value if defined? value
|
487
|
+
o.tag = tag if defined? tag
|
488
|
+
o.tag_class = tag_class if defined? tag_class
|
489
|
+
o.to_der
|
490
|
+
}
|
491
|
+
|
492
|
+
context 'value: SET' do
|
493
|
+
let(:value) { [s('hello'), i(42), s('world')] }
|
494
|
+
it { should == "\x31\x11\x02\x01\x2A\x04\x05hello\x04\x05world" }
|
495
|
+
end
|
496
|
+
|
497
|
+
context 'custom tag' do
|
498
|
+
let(:value) { [s('hello'), i(42), s('world')] }
|
499
|
+
let(:tag) { 14 }
|
500
|
+
let(:tag_class) { :PRIVATE }
|
501
|
+
it { should == "\xEE\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
|
502
|
+
end
|
503
|
+
|
504
|
+
context 'tag_class' do
|
505
|
+
let(:value) { [s('hello'), i(42), s('world')] }
|
506
|
+
let(:tag_class) { :APPLICATION }
|
507
|
+
it { should == "\x71\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
context "encodes infinite length values" do
|
512
|
+
subject do
|
513
|
+
asn1 = klass.new(value)
|
514
|
+
asn1.infinite_length = true
|
515
|
+
asn1.to_der
|
516
|
+
end
|
517
|
+
|
518
|
+
context "with explicit EOC" do
|
519
|
+
let(:value) { [
|
520
|
+
mod::Integer.new(1),
|
521
|
+
mod::Boolean.new(true),
|
522
|
+
mod::EndOfContents.new
|
523
|
+
] }
|
524
|
+
it { subject.should == "\x31\x80\x01\x01\xFF\x02\x01\x01\x00\x00" }
|
525
|
+
end
|
526
|
+
|
527
|
+
context "without explicit EOC" do
|
528
|
+
let(:value) { [
|
529
|
+
mod::Integer.new(1),
|
530
|
+
mod::Boolean.new(true),
|
531
|
+
] }
|
532
|
+
it { subject.should == "\x31\x80\x01\x01\xFF\x02\x01\x01\x00\x00" }
|
533
|
+
end
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
describe '#encode_to' do
|
538
|
+
context 'encodes to an IO' do
|
539
|
+
subject { klass.new(value).encode_to(io); io }
|
540
|
+
|
541
|
+
context "StringIO" do
|
542
|
+
let(:value) { [s(''), s(''), s('')] }
|
543
|
+
let(:io) { string_io_object }
|
544
|
+
its(:written_bytes) { should == "\x31\x06\x04\x00\x04\x00\x04\x00" }
|
545
|
+
end
|
546
|
+
|
547
|
+
context "Object responds to :write" do
|
548
|
+
let(:value) { [s(''), s(''), s('')] }
|
549
|
+
let(:io) { writable_object }
|
550
|
+
its(:written_bytes) { should == "\x31\x06\x04\x00\x04\x00\x04\x00" }
|
551
|
+
end
|
552
|
+
|
553
|
+
context "raise IO error transparently" do
|
554
|
+
let(:value) { [s(''), s(''), s('')] }
|
555
|
+
let(:io) { io_error_object }
|
556
|
+
it { -> { subject }.should raise_error asn1error }
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
it 'returns self' do
|
561
|
+
obj = klass.new([s(''), s(''), s('')])
|
562
|
+
obj.encode_to(string_io_object).should == obj
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
describe '#each' do
|
567
|
+
subject { yielded_value_from_each(klass.new(value)) }
|
568
|
+
|
569
|
+
context "yields each value in its order" do
|
570
|
+
let(:value) { [s('hello'), i(42), s('world')] }
|
571
|
+
it { should == value }
|
572
|
+
end
|
573
|
+
|
574
|
+
context "yields nothing for empty value" do
|
575
|
+
let(:value) { [] }
|
576
|
+
it { should == value }
|
577
|
+
end
|
578
|
+
|
579
|
+
it "is Enumerable via each" do
|
580
|
+
value = [s('hello'), i(42), s('world')]
|
581
|
+
klass.new(value).map { |e| e.value }.should == ['hello', 42, 'world']
|
582
|
+
end
|
583
|
+
|
584
|
+
it "returns Enumerator for blockless call" do
|
585
|
+
value = [s('hello'), i(42), s('world')]
|
586
|
+
klass.new(value).each.next.value.should == 'hello'
|
587
|
+
end
|
588
|
+
|
589
|
+
it "yields each value for an Enumerable" do
|
590
|
+
o = Object.new
|
591
|
+
def o.each
|
592
|
+
yield Krypt::ASN1::Integer.new(1)
|
593
|
+
yield Krypt::ASN1::Integer.new(2)
|
594
|
+
yield Krypt::ASN1::Integer.new(3)
|
595
|
+
end
|
596
|
+
klass.new(o).map { |e| e.value }.should == [1, 2, 3]
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
describe 'extracted from ASN1.decode' do
|
601
|
+
subject { decoder.decode(der) }
|
602
|
+
|
603
|
+
context 'extracted value' do
|
604
|
+
context 'SET' do
|
605
|
+
let(:der) { "\x31\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
|
606
|
+
its(:class) { should == klass }
|
607
|
+
its(:tag) { should == Krypt::ASN1::SET }
|
608
|
+
it 'contains decoded value' do
|
609
|
+
value = subject.value
|
610
|
+
value.size.should == 3
|
611
|
+
value[0].value == 'hello'
|
612
|
+
value[1].value == 42
|
613
|
+
value[2].value == 'world'
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
context 'SET OF Integer' do
|
618
|
+
let(:der) { "\x31\x0C\x02\x04\xFF\xFF\xFF\xFF\x02\x01\x00\x02\x01\x01" }
|
619
|
+
its(:class) { should == klass }
|
620
|
+
its(:tag) { should == Krypt::ASN1::SET }
|
621
|
+
it 'contains decoded value' do
|
622
|
+
value = subject.value
|
623
|
+
value.size.should == 3
|
624
|
+
value[0].value == -1
|
625
|
+
value[1].value == 0
|
626
|
+
value[2].value == 1
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
context '(empty)' do
|
631
|
+
let(:der) { "\x31\x00" }
|
632
|
+
its(:class) { should == klass }
|
633
|
+
its(:tag) { should == Krypt::ASN1::SET }
|
634
|
+
its(:value) { should == [] }
|
635
|
+
end
|
636
|
+
|
637
|
+
context '1000 elements' do
|
638
|
+
let(:der) { "\x31\x82\x0B\xB8" + "\x02\x01\x00" * 1000 }
|
639
|
+
its(:class) { should == klass }
|
640
|
+
its(:tag) { should == Krypt::ASN1::SET }
|
641
|
+
it 'contains decoded value' do
|
642
|
+
value = subject.value
|
643
|
+
value.size == 1000
|
644
|
+
value.all? { |v| v.value == 0 }.should be_true
|
645
|
+
end
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
context 'extracted tag class' do
|
650
|
+
context 'UNIVERSAL' do
|
651
|
+
let(:der) { "\x31\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
|
652
|
+
its(:tag_class) { should == :UNIVERSAL }
|
653
|
+
end
|
654
|
+
|
655
|
+
context 'APPLICATION' do
|
656
|
+
let(:der) { "\x71\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
|
657
|
+
its(:tag_class) { should == :APPLICATION }
|
658
|
+
end
|
659
|
+
|
660
|
+
context 'CONTEXT_SPECIFIC' do
|
661
|
+
let(:der) { "\xB1\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
|
662
|
+
its(:tag_class) { should == :CONTEXT_SPECIFIC }
|
663
|
+
end
|
664
|
+
|
665
|
+
context 'PRIVATE' do
|
666
|
+
let(:der) { "\xF1\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
|
667
|
+
its(:tag_class) { should == :PRIVATE }
|
668
|
+
end
|
669
|
+
|
670
|
+
context "setting IMPLICIT will result in CONTEXT_SPECIFIC" do
|
671
|
+
let(:der) { "\x31\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
|
672
|
+
it do
|
673
|
+
subject.tag_class = :IMPLICIT
|
674
|
+
subject.to_der.should == "\xB1\x11\x04\x05hello\x02\x01\x2A\x04\x05world"
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
context "setting EXPLICIT will reencode as CONTEXT_SPECIFIC" do
|
679
|
+
let(:der) { "\x31\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
|
680
|
+
it do
|
681
|
+
subject.tag_class = :EXPLICIT
|
682
|
+
subject.tag = 0
|
683
|
+
subject.to_der.should == "\xA0\x13\x31\x11\x02\x01\x2A\x04\x05hello\x04\x05world"
|
684
|
+
end
|
685
|
+
end
|
686
|
+
end
|
687
|
+
|
688
|
+
context "preserves wrongly encoded SET encodings" do
|
689
|
+
context "definite length" do
|
690
|
+
let(:der) { "\x31\x08\x05\x00\x02\x01\x01\x01\x01\xFF" }
|
691
|
+
it do
|
692
|
+
ary = subject.value
|
693
|
+
ary.size.should == 3
|
694
|
+
ary[0].tag.should == Krypt::ASN1::NULL
|
695
|
+
ary[1].tag.should == Krypt::ASN1::INTEGER
|
696
|
+
ary[2].tag.should == Krypt::ASN1::BOOLEAN
|
697
|
+
subject.to_der.should == der
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
701
|
+
context "infinite length" do
|
702
|
+
let(:der) { "\x31\x80\x05\x00\x02\x01\x01\x01\x01\xFF\x00\x00" }
|
703
|
+
it do
|
704
|
+
ary = subject.value
|
705
|
+
ary.size.should == 3
|
706
|
+
ary[0].tag.should == Krypt::ASN1::NULL
|
707
|
+
ary[1].tag.should == Krypt::ASN1::INTEGER
|
708
|
+
ary[2].tag.should == Krypt::ASN1::BOOLEAN
|
709
|
+
subject.to_der.should == der
|
710
|
+
end
|
711
|
+
end
|
712
|
+
|
713
|
+
context "reencodes the value in proper SET encoding when the set value is changed" do
|
714
|
+
let(:der) { "\x31\x08\x05\x00\x02\x01\x01\x01\x01\xFF" }
|
715
|
+
it do
|
716
|
+
subject.value = [
|
717
|
+
Krypt::ASN1::Null.new,
|
718
|
+
Krypt::ASN1::Integer.new(1),
|
719
|
+
Krypt::ASN1::Boolean.new(true)
|
720
|
+
]
|
721
|
+
subject.to_der.should == "\x31\x08\x01\x01\xFF\x02\x01\x01\x05\x00"
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
725
|
+
context "keeps the wrong SET order when an inner value is changed" do # would be too expensive to track
|
726
|
+
let(:der) { "\x31\x08\x05\x00\x02\x01\x01\x01\x01\xFF" }
|
727
|
+
it do
|
728
|
+
ary = subject.value
|
729
|
+
ary[1].value = 7
|
730
|
+
subject.to_der.should == "\x31\x08\x05\x00\x02\x01\x07\x01\x01\xFF"
|
731
|
+
end
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
735
|
+
context "preserves wrongly encoded SET OF encodings" do
|
736
|
+
context "definite length" do
|
737
|
+
let(:der) { "\x31\x0C\x04\x01b\x04\x03aaa\x04\x02aa" }
|
738
|
+
it do
|
739
|
+
ary = subject.value
|
740
|
+
ary.size.should == 3
|
741
|
+
ary[0].value.should == "b"
|
742
|
+
ary[1].value.should == "aaa"
|
743
|
+
ary[2].value.should == "aa"
|
744
|
+
subject.to_der.should == der
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
748
|
+
context "infinite length" do
|
749
|
+
let(:der) { "\x31\x80\x04\x01b\x04\x03aaa\x04\x02aa\x00\x00" }
|
750
|
+
it do
|
751
|
+
ary = subject.value
|
752
|
+
ary.size.should == 3
|
753
|
+
ary[0].value.should == "b"
|
754
|
+
ary[1].value.should == "aaa"
|
755
|
+
ary[2].value.should == "aa"
|
756
|
+
subject.to_der.should == der
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
context "reencodes the value in proper SET OF encoding when the set value is changed" do
|
761
|
+
let(:der) { "\x31\x0C\x04\x01b\x04\x03aaa\x04\x02aa" }
|
762
|
+
it do
|
763
|
+
subject.value = subject.value
|
764
|
+
subject.to_der.should == "\x31\x0C\x04\x01b\x04\x02aa\x04\x03aaa"
|
765
|
+
end
|
766
|
+
end
|
767
|
+
|
768
|
+
context "keeps the wrong SET order when an inner value is changed" do # would be too expensive to track
|
769
|
+
let(:der) { "\x31\x0C\x04\x01b\x04\x03aaa\x04\x02aa" }
|
770
|
+
it do
|
771
|
+
ary = subject.value
|
772
|
+
ary[0].value = "c"
|
773
|
+
subject.to_der.should == "\x31\x0C\x04\x01c\x04\x03aaa\x04\x02aa"
|
774
|
+
end
|
775
|
+
end
|
776
|
+
end
|
777
|
+
|
778
|
+
context 'extracted infinite_length' do
|
779
|
+
context 'definite encoding' do
|
780
|
+
let(:der) { "\x31\x11\x04\x05hello\x02\x01\x2A\x04\x05world" }
|
781
|
+
its(:infinite_length) { should == false }
|
782
|
+
end
|
783
|
+
|
784
|
+
context 'indefinite encoding' do
|
785
|
+
let(:der) { "\x31\x80\x04\x05hello\x02\x01\x2A\x04\x05world\x00\x00" }
|
786
|
+
its(:infinite_length) { should == true }
|
787
|
+
it "drops EndOfContents as last value" do
|
788
|
+
subject.value.size.should == 3
|
789
|
+
subject.value.any? { |o| o.instance_of? Krypt::ASN1::EndOfContents }.should be_false
|
790
|
+
end
|
791
|
+
end
|
792
|
+
end
|
793
|
+
end
|
794
|
+
end
|
795
|
+
|