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,351 @@
|
|
1
|
+
# encoding: US-ASCII
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'krypt'
|
5
|
+
require_relative '../resources'
|
6
|
+
|
7
|
+
|
8
|
+
shared_examples_for "a primitive declaration" do |func|
|
9
|
+
let(:asn1error) { Krypt::ASN1::ASN1Error }
|
10
|
+
subject do
|
11
|
+
n = name
|
12
|
+
o = opts
|
13
|
+
c = Class.new do
|
14
|
+
include Krypt::ASN1::Template::Sequence
|
15
|
+
send(func, n, o)
|
16
|
+
end
|
17
|
+
c.new
|
18
|
+
end
|
19
|
+
|
20
|
+
context "rejects declaration with no name" do
|
21
|
+
let(:name) { nil }
|
22
|
+
let(:opts) { nil }
|
23
|
+
specify { -> { subject }.should raise_error ArgumentError }
|
24
|
+
end
|
25
|
+
|
26
|
+
context "declararation with no options" do
|
27
|
+
let(:name) { :test }
|
28
|
+
let(:opts) { nil }
|
29
|
+
specify { subject.should respond_to name }
|
30
|
+
end
|
31
|
+
|
32
|
+
context "declaration with options" do
|
33
|
+
let(:name) { :test }
|
34
|
+
|
35
|
+
context "allows to mark as optional" do
|
36
|
+
let(:opts) { {optional: true} }
|
37
|
+
specify { subject.should respond_to name }
|
38
|
+
end
|
39
|
+
|
40
|
+
context "allows to set a tag" do
|
41
|
+
let(:opts) { {tag: 42} }
|
42
|
+
specify { subject.should respond_to name }
|
43
|
+
end
|
44
|
+
|
45
|
+
context "allows to set tagging" do
|
46
|
+
let(:opts) { {tagging: :EXPLICIT} }
|
47
|
+
specify { subject.should respond_to name }
|
48
|
+
end
|
49
|
+
|
50
|
+
context "allows to set tagging" do
|
51
|
+
let(:opts) { {tagging: :EXPLICIT} }
|
52
|
+
specify { subject.should respond_to name }
|
53
|
+
end
|
54
|
+
|
55
|
+
context "allows to set arbitrary default value" do
|
56
|
+
let(:opts) { {default: Object.new} }
|
57
|
+
specify { subject.should respond_to name }
|
58
|
+
end
|
59
|
+
|
60
|
+
context "allows to set optional, tag, tagging and default at once" do
|
61
|
+
let(:opts) { {optional: true, tag: 42, tagging: :IMPLICIT, default: Object.new} }
|
62
|
+
specify { subject.should respond_to name }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
shared_examples_for "a typed declaration" do |func|
|
68
|
+
let(:template) do
|
69
|
+
Class.new do
|
70
|
+
include Krypt::ASN1::Template::Sequence
|
71
|
+
asn1_integer :version
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
subject do
|
76
|
+
n = name
|
77
|
+
t = type
|
78
|
+
o = opts
|
79
|
+
c = Class.new do
|
80
|
+
include Krypt::ASN1::Template::Sequence
|
81
|
+
send(func, n, t, o)
|
82
|
+
end
|
83
|
+
c.new
|
84
|
+
end
|
85
|
+
|
86
|
+
context "rejects declaration with no name" do
|
87
|
+
let(:name) { nil }
|
88
|
+
let(:type) { template }
|
89
|
+
let(:opts) { nil }
|
90
|
+
specify { -> { subject }.should raise_error ArgumentError }
|
91
|
+
end
|
92
|
+
|
93
|
+
context "rejects declaration with no type" do
|
94
|
+
let(:name) { :test }
|
95
|
+
let(:type) { nil }
|
96
|
+
let(:opts) { nil }
|
97
|
+
specify { -> { subject }.should raise_error ArgumentError }
|
98
|
+
end
|
99
|
+
|
100
|
+
context "declararation with no options" do
|
101
|
+
let(:name) { :test }
|
102
|
+
let(:type) { template }
|
103
|
+
let(:opts) { nil }
|
104
|
+
specify { subject.should respond_to name }
|
105
|
+
end
|
106
|
+
|
107
|
+
context "declaration with options" do
|
108
|
+
let(:name) { :test }
|
109
|
+
let(:type) { template }
|
110
|
+
|
111
|
+
context "allows to mark as optional" do
|
112
|
+
let(:opts) { {optional: true} }
|
113
|
+
specify { subject.should respond_to name }
|
114
|
+
end
|
115
|
+
|
116
|
+
context "allows to set a tag" do
|
117
|
+
let(:opts) { {tag: 42} }
|
118
|
+
specify { subject.should respond_to name }
|
119
|
+
end
|
120
|
+
|
121
|
+
context "allows to set tagging" do
|
122
|
+
let(:opts) { {tagging: :EXPLICIT} }
|
123
|
+
specify { subject.should respond_to name }
|
124
|
+
end
|
125
|
+
|
126
|
+
context "allows to set tagging" do
|
127
|
+
let(:opts) { {tagging: :EXPLICIT} }
|
128
|
+
specify { subject.should respond_to name }
|
129
|
+
end
|
130
|
+
|
131
|
+
context "allows to set arbitrary default value" do
|
132
|
+
let(:opts) { {default: Object.new} }
|
133
|
+
specify { subject.should respond_to name }
|
134
|
+
end
|
135
|
+
|
136
|
+
context "allows to set optional, tag, tagging and default at once" do
|
137
|
+
let(:opts) { {optional: true, tag: 42, tagging: :IMPLICIT, default: Object.new} }
|
138
|
+
specify { subject.should respond_to name }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
shared_examples_for "Krypt::ASN1::Template" do
|
144
|
+
context "inclusion enables a set of DSL class methods" do
|
145
|
+
context("asn1_boolean") { it_behaves_like "a primitive declaration", :asn1_boolean }
|
146
|
+
context("asn1_integer") { it_behaves_like "a primitive declaration", :asn1_integer }
|
147
|
+
context("asn1_bit_string") { it_behaves_like "a primitive declaration", :asn1_bit_string }
|
148
|
+
context("asn1_octet_string") { it_behaves_like "a primitive declaration", :asn1_octet_string }
|
149
|
+
context("asn1_null") { it_behaves_like "a primitive declaration", :asn1_null }
|
150
|
+
context("asn1_object_id") { it_behaves_like "a primitive declaration", :asn1_object_id }
|
151
|
+
context("asn1_enumerated") { it_behaves_like "a primitive declaration", :asn1_enumerated }
|
152
|
+
context("asn1_utf8_string") { it_behaves_like "a primitive declaration", :asn1_utf8_string }
|
153
|
+
context("asn1_numeric_string") { it_behaves_like "a primitive declaration", :asn1_numeric_string }
|
154
|
+
context("asn1_printable_string") { it_behaves_like "a primitive declaration", :asn1_printable_string }
|
155
|
+
context("asn1_t61_string") { it_behaves_like "a primitive declaration", :asn1_t61_string }
|
156
|
+
context("asn1_videotex_string") { it_behaves_like "a primitive declaration", :asn1_videotex_string }
|
157
|
+
context("asn1_ia5_string") { it_behaves_like "a primitive declaration", :asn1_ia5_string }
|
158
|
+
context("asn1_utc_time") { it_behaves_like "a primitive declaration", :asn1_utc_time }
|
159
|
+
context("asn1_generalized_time") { it_behaves_like "a primitive declaration", :asn1_generalized_time }
|
160
|
+
context("asn1_graphic_string") { it_behaves_like "a primitive declaration", :asn1_graphic_string }
|
161
|
+
context("asn1_iso64_string") { it_behaves_like "a primitive declaration", :asn1_iso64_string }
|
162
|
+
context("asn1_general_string") { it_behaves_like "a primitive declaration", :asn1_general_string }
|
163
|
+
context("asn1_universal_string") { it_behaves_like "a primitive declaration", :asn1_universal_string }
|
164
|
+
context("asn1_bmp_string") { it_behaves_like "a primitive declaration", :asn1_bmp_string }
|
165
|
+
context("asn1_any") { it_behaves_like "a primitive declaration", :asn1_any }
|
166
|
+
|
167
|
+
context("asn1_template") { it_behaves_like "a typed declaration", :asn1_template }
|
168
|
+
context("asn1_sequence_of") { it_behaves_like "a typed declaration", :asn1_sequence_of }
|
169
|
+
context("asn1_set_of") { it_behaves_like "a typed declaration", :asn1_set_of }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
shared_examples_for "constructed type constructor" do |type|
|
174
|
+
let (:template) do
|
175
|
+
Class.new do
|
176
|
+
include type
|
177
|
+
asn1_integer :a
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
it "takes no-args" do
|
182
|
+
template.new.should be_an_instance_of template
|
183
|
+
end
|
184
|
+
|
185
|
+
it "takes a block and yields the new instance" do
|
186
|
+
template.new do |o|
|
187
|
+
o.should be_an_instance_of template
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
it "allows assignment to its fields once instantiated" do
|
192
|
+
o = template.new
|
193
|
+
o.a = 42
|
194
|
+
o.a.should == 42
|
195
|
+
end
|
196
|
+
|
197
|
+
it "allows assignment to its fields inside the block" do
|
198
|
+
obj = template.new do |o|
|
199
|
+
o.a = 42
|
200
|
+
end
|
201
|
+
obj.a.should == 42
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
shared_examples_for "DER-based equality with <=>" do |type|
|
206
|
+
let(:template) do
|
207
|
+
t = type
|
208
|
+
Class.new do
|
209
|
+
include t
|
210
|
+
asn1_integer :a
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
let(:tag) do
|
215
|
+
if type == Krypt::ASN1::Template::Sequence
|
216
|
+
"\x30"
|
217
|
+
elsif type == Krypt::ASN1::Template::Set
|
218
|
+
"\x31"
|
219
|
+
else
|
220
|
+
raise "only Set or Sequence"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
context "determines equality based on the encoding" do
|
225
|
+
let(:der) { "#{tag}\x03\x02\x01\x01" }
|
226
|
+
let(:v1) { template.parse_der(der) }
|
227
|
+
let(:v2) { template.parse_der(der) }
|
228
|
+
specify { v1.should == v2 && v1.eql?(v2).should == false }
|
229
|
+
end
|
230
|
+
|
231
|
+
context "finds a value encoded and reparsed to be equal to itself" do
|
232
|
+
let(:v1) { template.parse_der("#{tag}\x03\x02\x01\x01") }
|
233
|
+
specify { v1.should == (template.parse_der(v1.to_der)) }
|
234
|
+
end
|
235
|
+
|
236
|
+
context "when equal in terms of DER but not BER" do
|
237
|
+
let(:v1) { template.parse_der("#{tag}\x83\x00\x00\x03\x02\x01\x01") }
|
238
|
+
let(:v2) { template.parse_der("#{tag}\x03\x02\x01\x01") }
|
239
|
+
specify { v1.should_not == v2 }
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
shared_examples_for "accepting fields with special name" do |type, name|
|
244
|
+
let(:template) do
|
245
|
+
t = type
|
246
|
+
n = name
|
247
|
+
Class.new do
|
248
|
+
include t
|
249
|
+
asn1_integer name
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
let(:tag) do
|
254
|
+
if type == Krypt::ASN1::Template::Sequence
|
255
|
+
"\x30"
|
256
|
+
elsif type == Krypt::ASN1::Template::Set
|
257
|
+
"\x31"
|
258
|
+
else
|
259
|
+
raise "only Set or Sequence"
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
context "allows getting the value from a fresh instance" do
|
264
|
+
subject { template.new }
|
265
|
+
specify { subject.send(name).should be_nil }
|
266
|
+
end
|
267
|
+
|
268
|
+
context "allows getting the value from a parsed instance" do
|
269
|
+
subject { template.parse_der("#{tag}\x03\x02\x01\x01") }
|
270
|
+
specify { subject.send(name).should eq(1) }
|
271
|
+
end
|
272
|
+
|
273
|
+
context "allows setting the value on a fresh instance" do
|
274
|
+
subject { template.new }
|
275
|
+
specify { subject.send("#{name}=".to_sym, 2).should eq(2) }
|
276
|
+
end
|
277
|
+
|
278
|
+
context "allows setting the value on a parsed instance" do
|
279
|
+
subject { template.parse_der("#{tag}\x03\x02\x01\x01") }
|
280
|
+
specify do
|
281
|
+
obj = subject
|
282
|
+
obj.send(name).should eq(1)
|
283
|
+
obj.send("#{name}=".to_sym, 2).should eq(2)
|
284
|
+
obj.send(name).should eq(2)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
describe "Krypt::ASN1::Template::Sequence" do
|
290
|
+
it_behaves_like "Krypt::ASN1::Template"
|
291
|
+
it_behaves_like "constructed type constructor", Krypt::ASN1::Template::Sequence
|
292
|
+
it_behaves_like "DER-based equality with <=>", Krypt::ASN1::Template::Sequence
|
293
|
+
it_behaves_like "accepting fields with special name", Krypt::ASN1::Template::Sequence, :tag
|
294
|
+
it_behaves_like "accepting fields with special name", Krypt::ASN1::Template::Sequence, :type
|
295
|
+
end
|
296
|
+
|
297
|
+
describe "Krypt::ASN1::Template::Set" do
|
298
|
+
it_behaves_like "Krypt::ASN1::Template"
|
299
|
+
it_behaves_like "constructed type constructor", Krypt::ASN1::Template::Set
|
300
|
+
it_behaves_like "DER-based equality with <=>", Krypt::ASN1::Template::Set
|
301
|
+
it_behaves_like "accepting fields with special name", Krypt::ASN1::Template::Set, :tag
|
302
|
+
it_behaves_like "accepting fields with special name", Krypt::ASN1::Template::Set, :type
|
303
|
+
end
|
304
|
+
|
305
|
+
describe "Krypt::ASN1::Template::Choice" do
|
306
|
+
let (:template) do
|
307
|
+
Class.new do
|
308
|
+
include Krypt::ASN1::Template::Choice
|
309
|
+
asn1_integer
|
310
|
+
asn1_boolean
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
describe "#new" do
|
315
|
+
it "takes no-args" do
|
316
|
+
template.new.should be_an_instance_of template
|
317
|
+
end
|
318
|
+
|
319
|
+
it "takes a block and yields the new instance" do
|
320
|
+
template.new do |o|
|
321
|
+
o.should be_an_instance_of template
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
it "allows assignment to 'value' once instantiated" do
|
326
|
+
o = template.new
|
327
|
+
o.value = 42
|
328
|
+
o.value.should == 42
|
329
|
+
end
|
330
|
+
|
331
|
+
it "allows assignment to 'type' once instantiated" do
|
332
|
+
o = template.new
|
333
|
+
o.type = Krypt::ASN1::INTEGER
|
334
|
+
o.type.should == Krypt::ASN1::INTEGER
|
335
|
+
end
|
336
|
+
|
337
|
+
it "allows assignment to 'tag' once instantiated" do
|
338
|
+
o = template.new
|
339
|
+
o.tag = Krypt::ASN1::INTEGER
|
340
|
+
o.tag.should == Krypt::ASN1::INTEGER
|
341
|
+
end
|
342
|
+
|
343
|
+
it "allows assignment to 'value' inside the block" do
|
344
|
+
obj = template.new do |o|
|
345
|
+
o.value = 42
|
346
|
+
end
|
347
|
+
obj.value.should == 42
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# encoding: US-ASCII
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'krypt'
|
5
|
+
require_relative '../resources'
|
6
|
+
|
7
|
+
describe "Krypt::ASN1::Template::SequenceOf" do
|
8
|
+
SEQ_OF = Krypt::ASN1::Template::SequenceOf
|
9
|
+
let(:asn1error) { Krypt::ASN1::ASN1Error }
|
10
|
+
|
11
|
+
context "extracted from parse_der" do
|
12
|
+
subject { template.parse_der(der) }
|
13
|
+
let(:template) do
|
14
|
+
t = type
|
15
|
+
Class.new do
|
16
|
+
include SEQ_OF
|
17
|
+
asn1_type t
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "primitive contents" do
|
22
|
+
let(:type) { Krypt::ASN1::Integer }
|
23
|
+
let(:der) { "\x30\x06\x02\x01\x01\x02\x01\x01" }
|
24
|
+
its(:value) { should be_an_instance_of Array }
|
25
|
+
it { subject.value.size.should == 2 }
|
26
|
+
it { subject.value.all? { |v| v.instance_of?(Krypt::ASN1::Integer) && v.value == 1 }.should == true }
|
27
|
+
its(:to_der) { should == der }
|
28
|
+
end
|
29
|
+
|
30
|
+
context "template contents" do
|
31
|
+
context "SEQUENCE" do
|
32
|
+
let(:type) do
|
33
|
+
Class.new do
|
34
|
+
include Krypt::ASN1::Template::Sequence
|
35
|
+
asn1_boolean :a
|
36
|
+
end
|
37
|
+
end
|
38
|
+
let(:der) { "\x30\x0A\x30\x03\x01\x01\xFF\x30\x03\x01\x01\xFF" }
|
39
|
+
its(:value) { should be_an_instance_of Array }
|
40
|
+
it { subject.value.size.should == 2 }
|
41
|
+
it { subject.value.all? { |v| v.instance_of?(type) && v.a == true }.should == true }
|
42
|
+
its(:to_der) { should == der }
|
43
|
+
end
|
44
|
+
|
45
|
+
context "nested" do
|
46
|
+
let(:type) do
|
47
|
+
Class.new do
|
48
|
+
include SEQ_OF
|
49
|
+
asn1_type Krypt::ASN1::Integer
|
50
|
+
end
|
51
|
+
end
|
52
|
+
let(:der) { "\x30\x0D\x30\x06\x02\x01\x01\x02\x01\x01\x30\x03\x02\x01\x02" }
|
53
|
+
its(:value) { should be_an_instance_of Array }
|
54
|
+
it { subject.value.size.should == 2 }
|
55
|
+
it { subject.value[0].value.size.should == 2 }
|
56
|
+
it { subject.value[0].value.all? { |v| v.instance_of?(Krypt::ASN1::Integer) && v.value == 1 }.should == true }
|
57
|
+
it { subject.value[1].value.size.should == 1 }
|
58
|
+
it { subject.value[1].value.all? { |v| v.instance_of?(Krypt::ASN1::Integer) && v.value == 2 }.should == true }
|
59
|
+
its(:to_der) { should == der }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
@@ -0,0 +1,1241 @@
|
|
1
|
+
# encoding: US-ASCII
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'krypt'
|
5
|
+
require_relative '../resources'
|
6
|
+
|
7
|
+
|
8
|
+
describe "Krypt::ASN1::Template::Sequence" do
|
9
|
+
SEQ = Krypt::ASN1::Template::Sequence
|
10
|
+
let(:asn1error) { Krypt::ASN1::ASN1Error }
|
11
|
+
|
12
|
+
context "extracted from parse_der" do
|
13
|
+
subject { template.parse_der(der) }
|
14
|
+
|
15
|
+
context "single field" do
|
16
|
+
let(:template) do
|
17
|
+
Class.new do
|
18
|
+
include SEQ
|
19
|
+
asn1_integer :version
|
20
|
+
end
|
21
|
+
end
|
22
|
+
context "accepts correct encoding" do
|
23
|
+
let(:der) { "\x30\x03\x02\x01\x01" }
|
24
|
+
its(:version) { should == 1 }
|
25
|
+
it { subject.should be_an_instance_of template }
|
26
|
+
its(:to_der) { should == der }
|
27
|
+
end
|
28
|
+
context "rejects wrong encoding" do
|
29
|
+
let(:der) { "\x30\x03\x04\x01\x01" }
|
30
|
+
it { -> { subject.version }.should raise_error asn1error }
|
31
|
+
end
|
32
|
+
context "rejects encoding that is too long" do
|
33
|
+
let(:der) { "\x30\x06\x04\x01\x01\x04\x01\x01" }
|
34
|
+
it { -> { subject.version }.should raise_error asn1error }
|
35
|
+
end
|
36
|
+
context "rejects encoding that is not complete" do
|
37
|
+
let(:der) { "\x30\x03\x04\x01" }
|
38
|
+
it { -> { subject.version }.should raise_error asn1error }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "two fields" do
|
43
|
+
let(:template) do
|
44
|
+
Class.new do
|
45
|
+
include SEQ
|
46
|
+
asn1_integer :version
|
47
|
+
asn1_boolean :works?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
context "accepts correct encoding" do
|
51
|
+
let(:der) { "\x30\x06\x02\x01\x01\x01\x01\xFF" }
|
52
|
+
its(:version) { should == 1 }
|
53
|
+
its(:works?) { should == true }
|
54
|
+
it { subject.should be_an_instance_of template }
|
55
|
+
its(:to_der) { should == der }
|
56
|
+
end
|
57
|
+
context "rejects encodings where either field is missing" do
|
58
|
+
context "(first)" do
|
59
|
+
let(:der) { "\x30\x03\x01\x01\xFF" }
|
60
|
+
it { -> { subject.version }.should raise_error asn1error }
|
61
|
+
end
|
62
|
+
context "(second)" do
|
63
|
+
let(:der) { "\x30\x03\x02\x01\x01" }
|
64
|
+
it { -> { subject.version }.should raise_error asn1error }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "preserves non-DER encodings" do
|
70
|
+
let(:template) do
|
71
|
+
Class.new do
|
72
|
+
include SEQ
|
73
|
+
asn1_boolean :a
|
74
|
+
asn1_octet_string :b
|
75
|
+
end
|
76
|
+
end
|
77
|
+
let(:der) { "\x30\x83\x00\x00\x0D\x01\x01\xBB\x24\x80\x04\x01\x01\x04\x01\x02\x00\x00" }
|
78
|
+
its(:to_der) { should == der }
|
79
|
+
end
|
80
|
+
|
81
|
+
context "does not choke on invalid encodings" do
|
82
|
+
let(:template) do
|
83
|
+
Class.new do
|
84
|
+
include SEQ
|
85
|
+
asn1_integer :a
|
86
|
+
asn1_octet_string :b
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when parsing them" do
|
91
|
+
let(:der) { "\x30\x04\x00\x00\x22\x99" }
|
92
|
+
it { -> { subject }.should_not raise_error }
|
93
|
+
end
|
94
|
+
|
95
|
+
context "and encodes them again exactly as received" do
|
96
|
+
let(:der) { "\x30\x04\x00\x00\x22\x99" }
|
97
|
+
its(:to_der) { should == der }
|
98
|
+
end
|
99
|
+
|
100
|
+
context "but raises an error when accessing the fields" do
|
101
|
+
let(:der) { "\x30\x04\x00\x00\x22\x99" }
|
102
|
+
it { -> { subject.a }.should raise_error asn1error }
|
103
|
+
end
|
104
|
+
|
105
|
+
context "but raises an error if the tag doesn't match" do
|
106
|
+
let(:der) { "\x31\x06\x02\x01\x01\x04\x01a" }
|
107
|
+
it { -> { subject.a }.should raise_error asn1error }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context "tagged field" do
|
112
|
+
let(:template) do
|
113
|
+
t = tag
|
114
|
+
tg = tagging
|
115
|
+
Class.new do
|
116
|
+
include SEQ
|
117
|
+
asn1_integer :a, tag: t, tagging: tg
|
118
|
+
asn1_boolean :b
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
shared_examples_for "a non-constructed encoding" do |tagging, tag_byte|
|
123
|
+
context "accepts correct encoding" do
|
124
|
+
let(:der) { "\x30\x06#{tag_byte}\x01\x01\x01\x01\xFF" }
|
125
|
+
let(:tag) { 0 }
|
126
|
+
let(:tagging) { tagging }
|
127
|
+
its(:a) { should == 1 }
|
128
|
+
its(:b) { should == true }
|
129
|
+
its(:to_der) { should == der }
|
130
|
+
end
|
131
|
+
|
132
|
+
context "rejects wrong encoding" do
|
133
|
+
let(:der) { "\x30\x06\x02\x01\x01\x01\x01\xFF" }
|
134
|
+
let(:tag) { 0 }
|
135
|
+
let(:tagging) { tagging }
|
136
|
+
it { -> { subject.a }.should raise_error asn1error }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context ":IMPLICIT" do
|
141
|
+
it_behaves_like "a non-constructed encoding", :IMPLICIT, "\x80"
|
142
|
+
end
|
143
|
+
|
144
|
+
context ":EXPLICIT" do
|
145
|
+
context "accepts correct encoding" do
|
146
|
+
let(:der) { "\x30\x08\xA0\x03\x02\x01\x01\x01\x01\xFF" }
|
147
|
+
let(:tag) { 0 }
|
148
|
+
let(:tagging) { :EXPLICIT }
|
149
|
+
its(:a) { should == 1 }
|
150
|
+
its(:b) { should == true }
|
151
|
+
its(:to_der) { should == der }
|
152
|
+
end
|
153
|
+
|
154
|
+
context "reject wrong encoding (non-constructed)" do
|
155
|
+
let(:der) { "\x30\x08\x80\x03\x02\x01\x01\x01\x01\xFF" }
|
156
|
+
let(:tag) { 0 }
|
157
|
+
let(:tagging) { :EXPLICIT }
|
158
|
+
it { -> { subject.a }.should raise_error asn1error }
|
159
|
+
end
|
160
|
+
|
161
|
+
context "reject wrong encoding" do
|
162
|
+
let(:der) { "\x30\x06\x80\x01\x01\x01\x01\xFF" }
|
163
|
+
let(:tag) { 0 }
|
164
|
+
let(:tagging) { :EXPLICIT }
|
165
|
+
it { -> { subject.a }.should raise_error asn1error }
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context ":CONTEXT_SPECIFIC" do
|
170
|
+
it_behaves_like "a non-constructed encoding", :IMPLICIT, "\x80"
|
171
|
+
end
|
172
|
+
|
173
|
+
context ":APPLICATION" do
|
174
|
+
it_behaves_like "a non-constructed encoding", :APPLICATION, "\x40"
|
175
|
+
end
|
176
|
+
|
177
|
+
context ":PRIVATE" do
|
178
|
+
it_behaves_like "a non-constructed encoding", :PRIVATE, "\xC0"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
context "optional first field" do
|
183
|
+
let(:template) do
|
184
|
+
Class.new do
|
185
|
+
include SEQ
|
186
|
+
asn1_integer :a, optional: true
|
187
|
+
asn1_boolean :b
|
188
|
+
asn1_octet_string :c
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context "present" do
|
193
|
+
let(:der) { "\x30\x09\x02\x01\x01\x01\x01\xFF\x04\x01a" }
|
194
|
+
its(:a) { should == 1 }
|
195
|
+
its(:b) { should == true }
|
196
|
+
its(:c) { should == "a" }
|
197
|
+
it { subject.should be_an_instance_of template }
|
198
|
+
its(:to_der) { should == der }
|
199
|
+
end
|
200
|
+
|
201
|
+
context "absent" do
|
202
|
+
let(:der) { "\x30\x06\x01\x01\xFF\x04\x01a" }
|
203
|
+
its(:a) { should be_nil }
|
204
|
+
its(:b) { should == true }
|
205
|
+
its(:c) { should == "a" }
|
206
|
+
it { subject.should be_an_instance_of template }
|
207
|
+
its(:to_der) { should == der }
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context "optional field between others" do
|
212
|
+
let(:template) do
|
213
|
+
Class.new do
|
214
|
+
include SEQ
|
215
|
+
asn1_integer :a
|
216
|
+
asn1_boolean :b, optional: true
|
217
|
+
asn1_octet_string :c
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context "present" do
|
222
|
+
let(:der) { "\x30\x09\x02\x01\x01\x01\x01\xFF\x04\x01a" }
|
223
|
+
its(:a) { should == 1 }
|
224
|
+
its(:b) { should == true }
|
225
|
+
its(:c) { should == "a" }
|
226
|
+
it { subject.should be_an_instance_of template }
|
227
|
+
its(:to_der) { should == der }
|
228
|
+
end
|
229
|
+
|
230
|
+
context "absent" do
|
231
|
+
let(:der) { "\x30\x06\x02\x01\x01\x04\x01a" }
|
232
|
+
its(:a) { should == 1 }
|
233
|
+
its(:b) { should be_nil }
|
234
|
+
its(:c) { should == "a" }
|
235
|
+
it { subject.should be_an_instance_of template }
|
236
|
+
its(:to_der) { should == der }
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
context "optional field at end" do
|
241
|
+
let(:template) do
|
242
|
+
Class.new do
|
243
|
+
include SEQ
|
244
|
+
asn1_integer :a
|
245
|
+
asn1_boolean :b
|
246
|
+
asn1_octet_string :c, optional: true
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context "present" do
|
251
|
+
let(:der) { "\x30\x09\x02\x01\x01\x01\x01\xFF\x04\x01a" }
|
252
|
+
its(:a) { should == 1 }
|
253
|
+
its(:b) { should == true }
|
254
|
+
its(:c) { should == "a" }
|
255
|
+
it { subject.should be_an_instance_of template }
|
256
|
+
its(:to_der) { should == der }
|
257
|
+
end
|
258
|
+
|
259
|
+
context "absent" do
|
260
|
+
let(:der) { "\x30\x06\x02\x01\x01\x01\x01\xFF" }
|
261
|
+
its(:a) { should == 1 }
|
262
|
+
its(:b) { should == true }
|
263
|
+
its(:c) { should be_nil }
|
264
|
+
it { subject.should be_an_instance_of template }
|
265
|
+
its(:to_der) { should == der }
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
context "multiple optional fields at end" do
|
270
|
+
let(:template) do
|
271
|
+
Class.new do
|
272
|
+
include SEQ
|
273
|
+
asn1_integer :a
|
274
|
+
asn1_boolean :b
|
275
|
+
asn1_octet_string :c, optional: true
|
276
|
+
asn1_t61_string :d, optional: true
|
277
|
+
asn1_ia5_string :e, optional: true
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
context "all present" do
|
282
|
+
let(:der) { "\x30\x0F\x02\x01\x01\x01\x01\xFF\x04\x01a\x14\x01b\x16\x01c" }
|
283
|
+
its(:a) { should == 1 }
|
284
|
+
its(:b) { should == true }
|
285
|
+
its(:c) { should == "a" }
|
286
|
+
its(:d) { should == "b" }
|
287
|
+
its(:e) { should == "c" }
|
288
|
+
it { subject.should be_an_instance_of template }
|
289
|
+
its(:to_der) { should == der }
|
290
|
+
end
|
291
|
+
|
292
|
+
context "first absent" do
|
293
|
+
let(:der) { "\x30\x0C\x02\x01\x01\x01\x01\xFF\x14\x01b\x16\x01c" }
|
294
|
+
its(:a) { should == 1 }
|
295
|
+
its(:b) { should == true }
|
296
|
+
its(:c) { should be_nil }
|
297
|
+
its(:d) { should == "b" }
|
298
|
+
its(:e) { should == "c" }
|
299
|
+
it { subject.should be_an_instance_of template }
|
300
|
+
its(:to_der) { should == der }
|
301
|
+
end
|
302
|
+
|
303
|
+
context "absent between others" do
|
304
|
+
let(:der) { "\x30\x0C\x02\x01\x01\x01\x01\xFF\x04\x01a\x16\x01c" }
|
305
|
+
its(:a) { should == 1 }
|
306
|
+
its(:b) { should == true }
|
307
|
+
its(:c) { should == "a" }
|
308
|
+
its(:d) { should be_nil }
|
309
|
+
its(:e) { should == "c" }
|
310
|
+
it { subject.should be_an_instance_of template }
|
311
|
+
its(:to_der) { should == der }
|
312
|
+
end
|
313
|
+
|
314
|
+
context "last absent" do
|
315
|
+
let(:der) { "\x30\x0C\x02\x01\x01\x01\x01\xFF\x04\x01a\x14\x01b" }
|
316
|
+
its(:a) { should == 1 }
|
317
|
+
its(:b) { should == true }
|
318
|
+
its(:c) { should == "a" }
|
319
|
+
its(:d) { should == "b"}
|
320
|
+
its(:e) { should be_nil }
|
321
|
+
it { subject.should be_an_instance_of template }
|
322
|
+
its(:to_der) { should == der }
|
323
|
+
end
|
324
|
+
|
325
|
+
context "all absent" do
|
326
|
+
let(:der) { "\x30\x06\x02\x01\x01\x01\x01\xFF" }
|
327
|
+
its(:a) { should == 1 }
|
328
|
+
its(:b) { should == true }
|
329
|
+
its(:c) { should be_nil }
|
330
|
+
its(:d) { should be_nil }
|
331
|
+
its(:e) { should be_nil }
|
332
|
+
it { subject.should be_an_instance_of template }
|
333
|
+
its(:to_der) { should == der }
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
context "single first default value field" do
|
338
|
+
let(:template) do
|
339
|
+
Class.new do
|
340
|
+
include SEQ
|
341
|
+
asn1_integer :a, default: 42
|
342
|
+
asn1_boolean :b
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
context "present" do
|
347
|
+
let(:der) { "\x30\x06\x02\x01\x01\x01\x01\xFF" }
|
348
|
+
its(:a) { should == 1 }
|
349
|
+
its(:b) { should == true }
|
350
|
+
it { subject.should be_an_instance_of template }
|
351
|
+
its(:to_der) { should == der }
|
352
|
+
end
|
353
|
+
|
354
|
+
context "absent" do
|
355
|
+
let(:der) { "\x30\x03\x01\x01\xFF" }
|
356
|
+
its(:a) { should == 42 }
|
357
|
+
its(:b) { should == true }
|
358
|
+
it { subject.should be_an_instance_of template }
|
359
|
+
its(:to_der) { should == der }
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
context "default value field between others" do
|
364
|
+
let(:template) do
|
365
|
+
Class.new do
|
366
|
+
include SEQ
|
367
|
+
asn1_integer :a
|
368
|
+
asn1_boolean :b, default: false
|
369
|
+
asn1_octet_string :c
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
context "present" do
|
374
|
+
let(:der) { "\x30\x09\x02\x01\x01\x01\x01\xFF\x04\x01a" }
|
375
|
+
its(:a) { should == 1 }
|
376
|
+
its(:b) { should == true }
|
377
|
+
its(:c) { should == "a" }
|
378
|
+
it { subject.should be_an_instance_of template }
|
379
|
+
its(:to_der) { should == der }
|
380
|
+
end
|
381
|
+
|
382
|
+
context "absent" do
|
383
|
+
let(:der) { "\x30\x06\x02\x01\x01\x04\x01a" }
|
384
|
+
its(:a) { should == 1 }
|
385
|
+
its(:b) { should == false }
|
386
|
+
its(:c) { should == "a" }
|
387
|
+
it { subject.should be_an_instance_of template }
|
388
|
+
its(:to_der) { should == der }
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
context "default value field at end" do
|
393
|
+
let(:template) do
|
394
|
+
Class.new do
|
395
|
+
include SEQ
|
396
|
+
asn1_integer :a
|
397
|
+
asn1_boolean :b
|
398
|
+
asn1_octet_string :c, default: "b"
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
context "present" do
|
403
|
+
let(:der) { "\x30\x09\x02\x01\x01\x01\x01\xFF\x04\x01a" }
|
404
|
+
its(:a) { should == 1 }
|
405
|
+
its(:b) { should == true }
|
406
|
+
its(:c) { should == "a" }
|
407
|
+
it { subject.should be_an_instance_of template }
|
408
|
+
its(:to_der) { should == der }
|
409
|
+
end
|
410
|
+
|
411
|
+
context "absent" do
|
412
|
+
let(:der) { "\x30\x06\x02\x01\x01\x01\x01\xFF" }
|
413
|
+
its(:a) { should == 1 }
|
414
|
+
its(:b) { should == true }
|
415
|
+
its(:c) { should == "b" }
|
416
|
+
it { subject.should be_an_instance_of template }
|
417
|
+
its(:to_der) { should == der }
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
context "multiple default value fields at end" do
|
422
|
+
let(:template) do
|
423
|
+
Class.new do
|
424
|
+
include SEQ
|
425
|
+
asn1_integer :a
|
426
|
+
asn1_boolean :b
|
427
|
+
asn1_octet_string :c, default: "a"
|
428
|
+
asn1_t61_string :d, default: "a"
|
429
|
+
asn1_ia5_string :e, default: "a"
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
context "all present" do
|
434
|
+
let(:der) { "\x30\x0F\x02\x01\x01\x01\x01\xFF\x04\x01b\x14\x01b\x16\x01b" }
|
435
|
+
its(:a) { should == 1 }
|
436
|
+
its(:b) { should == true }
|
437
|
+
its(:c) { should == "b" }
|
438
|
+
its(:d) { should == "b" }
|
439
|
+
its(:e) { should == "b" }
|
440
|
+
it { subject.should be_an_instance_of template }
|
441
|
+
its(:to_der) { should == der }
|
442
|
+
end
|
443
|
+
|
444
|
+
context "first absent" do
|
445
|
+
let(:der) { "\x30\x0C\x02\x01\x01\x01\x01\xFF\x14\x01b\x16\x01b" }
|
446
|
+
its(:a) { should == 1 }
|
447
|
+
its(:b) { should == true }
|
448
|
+
its(:c) { should == "a" }
|
449
|
+
its(:d) { should == "b" }
|
450
|
+
its(:e) { should == "b" }
|
451
|
+
it { subject.should be_an_instance_of template }
|
452
|
+
its(:to_der) { should == der }
|
453
|
+
end
|
454
|
+
|
455
|
+
context "absent between others" do
|
456
|
+
let(:der) { "\x30\x0C\x02\x01\x01\x01\x01\xFF\x04\x01b\x16\x01b" }
|
457
|
+
its(:a) { should == 1 }
|
458
|
+
its(:b) { should == true }
|
459
|
+
its(:c) { should == "b" }
|
460
|
+
its(:d) { should == "a" }
|
461
|
+
its(:e) { should == "b" }
|
462
|
+
it { subject.should be_an_instance_of template }
|
463
|
+
its(:to_der) { should == der }
|
464
|
+
end
|
465
|
+
|
466
|
+
context "last absent" do
|
467
|
+
let(:der) { "\x30\x0C\x02\x01\x01\x01\x01\xFF\x04\x01b\x14\x01b" }
|
468
|
+
its(:a) { should == 1 }
|
469
|
+
its(:b) { should == true }
|
470
|
+
its(:c) { should == "b" }
|
471
|
+
its(:d) { should == "b"}
|
472
|
+
its(:e) { should == "a" }
|
473
|
+
it { subject.should be_an_instance_of template }
|
474
|
+
its(:to_der) { should == der }
|
475
|
+
end
|
476
|
+
|
477
|
+
context "all absent" do
|
478
|
+
let(:der) { "\x30\x06\x02\x01\x01\x01\x01\xFF" }
|
479
|
+
its(:a) { should == 1 }
|
480
|
+
its(:b) { should == true }
|
481
|
+
its(:c) { should == "a" }
|
482
|
+
its(:d) { should == "a" }
|
483
|
+
its(:e) { should == "a" }
|
484
|
+
it { subject.should be_an_instance_of template }
|
485
|
+
its(:to_der) { should == der }
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
context "default value and optional fields mixed at beginning" do
|
490
|
+
let(:template) do
|
491
|
+
Class.new do
|
492
|
+
include SEQ
|
493
|
+
asn1_octet_string :a, optional: true
|
494
|
+
asn1_t61_string :b, default: "a"
|
495
|
+
asn1_ia5_string :c, default: "a"
|
496
|
+
asn1_integer :d
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
context "all present" do
|
501
|
+
let(:der) { "\x30\x0C\x04\x01b\x14\x01b\x16\x01b\x02\x01\x01" }
|
502
|
+
its(:a) { should == "b" }
|
503
|
+
its(:b) { should == "b" }
|
504
|
+
its(:c) { should == "b" }
|
505
|
+
its(:d) { should == 1 }
|
506
|
+
its(:to_der) { should == der }
|
507
|
+
end
|
508
|
+
|
509
|
+
context "all absent" do
|
510
|
+
let(:der) { "\x30\x03\x02\x01\x01" }
|
511
|
+
its(:a) { should be_nil }
|
512
|
+
its(:b) { should == "a" }
|
513
|
+
its(:c) { should == "a" }
|
514
|
+
its(:d) { should == 1 }
|
515
|
+
its(:to_der) { should == der }
|
516
|
+
end
|
517
|
+
|
518
|
+
context "rejects otherwise correct encoding if stream is not consumed" do
|
519
|
+
let(:der) { "\x30\x06\x02\x01\x01\x04\x01\x01" } # :d is matched, all others optional or default
|
520
|
+
it { -> { subject.a }.should raise_error asn1error }
|
521
|
+
end
|
522
|
+
|
523
|
+
context "rejects when wrong encoding is given for an optional field" do
|
524
|
+
let(:der) { "\x30\x0C\x01\x01\x00\x14\x01b\x16\x01b\x02\x01\x01" }
|
525
|
+
it { -> { subject.a }.should raise_error asn1error }
|
526
|
+
end
|
527
|
+
|
528
|
+
context "rejects when wrong encoding is given for a default field" do
|
529
|
+
let(:der) { "\x30\x0C\x04\x01\x01\x04\x01b\x16\x01b\x02\x01\x01" }
|
530
|
+
it { -> { subject.a }.should raise_error asn1error }
|
531
|
+
end
|
532
|
+
|
533
|
+
context "rejects when wrong encoding is given for a default field and the
|
534
|
+
optional field is omitted" do
|
535
|
+
let(:der) { "\x30\x09\x01\x01\xFF\x16\x01b\x02\x01\x01" }
|
536
|
+
it { -> { subject.a }.should raise_error asn1error }
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
context "default value and optional fields mixed at end" do
|
541
|
+
let(:template) do
|
542
|
+
Class.new do
|
543
|
+
include SEQ
|
544
|
+
asn1_integer :a
|
545
|
+
asn1_octet_string :b, optional: true
|
546
|
+
asn1_t61_string :c, default: "a"
|
547
|
+
asn1_ia5_string :d, default: "a"
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
context "all present" do
|
552
|
+
let(:der) { "\x30\x0C\x02\x01\x01\x04\x01b\x14\x01b\x16\x01b" }
|
553
|
+
its(:a) { should == 1 }
|
554
|
+
its(:b) { should == "b" }
|
555
|
+
its(:c) { should == "b" }
|
556
|
+
its(:d) { should == "b" }
|
557
|
+
its(:to_der) { should == der }
|
558
|
+
end
|
559
|
+
|
560
|
+
context "all absent" do
|
561
|
+
let(:der) { "\x30\x03\x02\x01\x01" }
|
562
|
+
its(:a) { should == 1 }
|
563
|
+
its(:b) { should be_nil }
|
564
|
+
its(:c) { should == "a" }
|
565
|
+
its(:d) { should == "a" }
|
566
|
+
its(:to_der) { should == der }
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
context "inner template" do
|
571
|
+
let(:template2) do
|
572
|
+
Class.new do
|
573
|
+
include SEQ
|
574
|
+
asn1_boolean :a
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
context "at beginning" do
|
579
|
+
let(:template) do
|
580
|
+
t = template2
|
581
|
+
Class.new do
|
582
|
+
include SEQ
|
583
|
+
asn1_template :a, t
|
584
|
+
asn1_integer :b
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
context "accepts valid encoding" do
|
589
|
+
let(:der) { "\x30\x08\x30\x03\x01\x01\xFF\x02\x01\x01" }
|
590
|
+
its(:a) { should be_an_instance_of template2 }
|
591
|
+
it { subject.a.a.should == true }
|
592
|
+
its(:b) { should == 1 }
|
593
|
+
its(:to_der) { should == der }
|
594
|
+
end
|
595
|
+
|
596
|
+
context "rejects wrong encoding" do
|
597
|
+
let(:der) { "\x30\x06\x01\x01\xFF\x02\x01\x01" }
|
598
|
+
it { -> { subject.a }.should raise_error asn1error }
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
context "at end" do
|
603
|
+
let(:template) do
|
604
|
+
t = template2
|
605
|
+
Class.new do
|
606
|
+
include SEQ
|
607
|
+
asn1_integer :a
|
608
|
+
asn1_template :b, t
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
context "accepts valid encoding" do
|
613
|
+
let(:der) { "\x30\x08\x02\x01\x01\x30\x03\x01\x01\xFF" }
|
614
|
+
its(:a) { should == 1 }
|
615
|
+
its(:b) { should be_an_instance_of template2 }
|
616
|
+
it { subject.b.a.should == true }
|
617
|
+
its(:to_der) { should == der }
|
618
|
+
end
|
619
|
+
|
620
|
+
context "rejects wrong encoding" do
|
621
|
+
let(:der) { "\x31\x08\x02\x01\x01\x30\x03\x01\x01\xFF" }
|
622
|
+
it { -> { subject.a }.should raise_error asn1error }
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
context "with implicit tagging" do
|
627
|
+
let(:template) do
|
628
|
+
t = template2
|
629
|
+
Class.new do
|
630
|
+
include SEQ
|
631
|
+
asn1_template :a, t, tag: 0, tagging: :IMPLICIT
|
632
|
+
asn1_integer :b
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
context "accepts valid encoding" do
|
637
|
+
let(:der) { "\x30\x08\xA0\x03\x01\x01\xFF\x02\x01\x01" }
|
638
|
+
its(:a) { should be_an_instance_of template2 }
|
639
|
+
it { subject.a.a.should == true }
|
640
|
+
its(:b) { should == 1 }
|
641
|
+
its(:to_der) { should == der }
|
642
|
+
end
|
643
|
+
|
644
|
+
context "rejects wrong encoding" do
|
645
|
+
let(:der) { "\x30\x08\x30\x03\x01\x01\xFF\x02\x01\x01" }
|
646
|
+
it { -> { subject.a }.should raise_error asn1error }
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
650
|
+
context "with explicit tagging" do
|
651
|
+
let(:template) do
|
652
|
+
t = template2
|
653
|
+
Class.new do
|
654
|
+
include SEQ
|
655
|
+
asn1_template :a, t, tag: 0, tagging: :EXPLICIT
|
656
|
+
asn1_integer :b
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
660
|
+
context "accepts valid encoding" do
|
661
|
+
let(:der) { "\x30\x0A\xA0\x05\x30\x03\x01\x01\xFF\x02\x01\x01" }
|
662
|
+
its(:a) { should be_an_instance_of template2 }
|
663
|
+
it { subject.a.a.should == true }
|
664
|
+
its(:b) { should == 1 }
|
665
|
+
its(:to_der) { should == der }
|
666
|
+
end
|
667
|
+
|
668
|
+
context "rejects wrong encoding" do
|
669
|
+
let(:der) { "\x30\x08\x30\x03\x01\x01\xFF\x02\x01\x01" }
|
670
|
+
it { -> { subject.a }.should raise_error asn1error }
|
671
|
+
end
|
672
|
+
end
|
673
|
+
|
674
|
+
context "optional" do
|
675
|
+
let(:template) do
|
676
|
+
t = template2
|
677
|
+
Class.new do
|
678
|
+
include SEQ
|
679
|
+
asn1_template :a, t, optional: true
|
680
|
+
asn1_integer :b
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
context "present" do
|
685
|
+
let(:der) { "\x30\x08\x30\x03\x01\x01\xFF\x02\x01\x01" }
|
686
|
+
its(:a) { should be_an_instance_of template2 }
|
687
|
+
it { subject.a.a.should == true }
|
688
|
+
its(:b) { should == 1 }
|
689
|
+
its(:to_der) { should == der }
|
690
|
+
end
|
691
|
+
|
692
|
+
context "absent" do
|
693
|
+
let(:der) { "\x30\x03\x02\x01\x01" }
|
694
|
+
its(:a) { should be_nil }
|
695
|
+
its(:b) { should == 1 }
|
696
|
+
its(:to_der) { should == der }
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
700
|
+
context "with default value at beginning" do
|
701
|
+
let(:template) do
|
702
|
+
t = template2
|
703
|
+
obj = t.new
|
704
|
+
obj.a = false
|
705
|
+
Class.new do
|
706
|
+
include SEQ
|
707
|
+
asn1_template :a, t, default: obj
|
708
|
+
asn1_integer :b
|
709
|
+
end
|
710
|
+
end
|
711
|
+
|
712
|
+
context "present" do
|
713
|
+
let(:der) { "\x30\x08\x30\x03\x01\x01\xFF\x02\x01\x01" }
|
714
|
+
its(:a) { should be_an_instance_of template2 }
|
715
|
+
it { subject.a.a.should == true }
|
716
|
+
its(:b) { should == 1 }
|
717
|
+
its(:to_der) { should == der }
|
718
|
+
end
|
719
|
+
|
720
|
+
context "absent" do
|
721
|
+
let(:der) { "\x30\x03\x02\x01\x01" }
|
722
|
+
its(:a) { should be_an_instance_of template2 }
|
723
|
+
it { subject.a.a.should == false }
|
724
|
+
its(:b) { should == 1 }
|
725
|
+
its(:to_der) { should == der }
|
726
|
+
end
|
727
|
+
end
|
728
|
+
|
729
|
+
context "with default value at end" do
|
730
|
+
let(:template) do
|
731
|
+
t = template2
|
732
|
+
obj = t.new
|
733
|
+
obj.a = false
|
734
|
+
Class.new do
|
735
|
+
include SEQ
|
736
|
+
asn1_integer :a
|
737
|
+
asn1_template :b, t, default: obj
|
738
|
+
end
|
739
|
+
end
|
740
|
+
|
741
|
+
context "present" do
|
742
|
+
let(:der) { "\x30\x08\x02\x01\x01\x30\x03\x01\x01\xFF" }
|
743
|
+
its(:a) { should == 1 }
|
744
|
+
its(:b) { should be_an_instance_of template2 }
|
745
|
+
it { subject.b.a.should == true }
|
746
|
+
its(:to_der) { should == der }
|
747
|
+
end
|
748
|
+
|
749
|
+
context "absent" do
|
750
|
+
let(:der) { "\x30\x03\x02\x01\x01" }
|
751
|
+
its(:a) { should == 1 }
|
752
|
+
its(:b) { should be_an_instance_of template2 }
|
753
|
+
it { subject.b.a.should == false }
|
754
|
+
its(:to_der) { should == der }
|
755
|
+
end
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
759
|
+
context "SEQUENCE OF" do
|
760
|
+
context "standard" do
|
761
|
+
let(:template) do
|
762
|
+
t = type
|
763
|
+
Class.new do
|
764
|
+
include SEQ
|
765
|
+
asn1_sequence_of :a, t
|
766
|
+
end
|
767
|
+
end
|
768
|
+
|
769
|
+
context "multiple Templates" do
|
770
|
+
let(:template2) do
|
771
|
+
Class.new do
|
772
|
+
include SEQ
|
773
|
+
asn1_integer :a
|
774
|
+
end
|
775
|
+
end
|
776
|
+
let(:type) { template2 }
|
777
|
+
let(:der) { "\x30\x0C\x30\x0A\x30\x03\x02\x01\x01\x30\x03\x02\x01\x01" }
|
778
|
+
its(:a) { should be_an_instance_of Array }
|
779
|
+
it { subject.a.size.should == 2 }
|
780
|
+
it { subject.a.all? { |asn1| asn1.instance_of?(type) && asn1.a == 1 }.should == true }
|
781
|
+
its(:to_der) { should == der }
|
782
|
+
end
|
783
|
+
|
784
|
+
context "multiple Primitives" do
|
785
|
+
let(:type) { Krypt::ASN1::Integer }
|
786
|
+
let(:der) { "\x30\x08\x30\x06\x02\x01\x01\x02\x01\x01" }
|
787
|
+
its(:a) { should be_an_instance_of Array }
|
788
|
+
it { subject.a.size.should == 2 }
|
789
|
+
it { subject.a.all? { |asn1| asn1.instance_of?(type) && asn1.value == 1 }.should == true }
|
790
|
+
its(:to_der) { should == der }
|
791
|
+
end
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
795
|
+
context "SET OF" do
|
796
|
+
context "standard" do
|
797
|
+
let(:template) do
|
798
|
+
t = type
|
799
|
+
Class.new do
|
800
|
+
include SEQ
|
801
|
+
asn1_set_of :a, t
|
802
|
+
end
|
803
|
+
end
|
804
|
+
|
805
|
+
context "multiple Templates" do
|
806
|
+
let(:template2) do
|
807
|
+
Class.new do
|
808
|
+
include SEQ
|
809
|
+
asn1_integer :a
|
810
|
+
end
|
811
|
+
end
|
812
|
+
let(:type) { template2 }
|
813
|
+
let(:der) { "\x30\x0C\x31\x0A\x30\x03\x02\x01\x01\x30\x03\x02\x01\x01" }
|
814
|
+
its(:a) { should be_an_instance_of Array }
|
815
|
+
it { subject.a.size.should == 2 }
|
816
|
+
it { subject.a.all? { |asn1| asn1.instance_of?(type) && asn1.a == 1 }.should == true }
|
817
|
+
its(:to_der) { should == der }
|
818
|
+
end
|
819
|
+
|
820
|
+
context "multiple Primitives" do
|
821
|
+
let(:type) { Krypt::ASN1::Integer }
|
822
|
+
let(:der) { "\x30\x08\x31\x06\x02\x01\x01\x02\x01\x01" }
|
823
|
+
its(:a) { should be_an_instance_of Array }
|
824
|
+
it { subject.a.size.should == 2 }
|
825
|
+
it { subject.a.all? { |asn1| asn1.instance_of?(type) && asn1.value == 1 }.should == true }
|
826
|
+
its(:to_der) { should == der }
|
827
|
+
end
|
828
|
+
end
|
829
|
+
end
|
830
|
+
|
831
|
+
context "ANY values" do
|
832
|
+
context "at beginning" do
|
833
|
+
let(:template) do
|
834
|
+
Class.new do
|
835
|
+
include SEQ
|
836
|
+
asn1_any :a
|
837
|
+
asn1_boolean :b
|
838
|
+
end
|
839
|
+
end
|
840
|
+
|
841
|
+
context "as primitive value" do
|
842
|
+
let(:der) { "\x30\x06\x02\x01\x01\x01\x01\xFF" }
|
843
|
+
its(:a) { should be_an_instance_of Krypt::ASN1::Integer }
|
844
|
+
it { subject.a.value.should == 1 }
|
845
|
+
its(:b) { should == true }
|
846
|
+
its(:to_der) { should == der }
|
847
|
+
end
|
848
|
+
|
849
|
+
context "as sequence" do
|
850
|
+
let(:der) { "\x30\x0B\x30\x06\x02\x01\x01\x02\x01\x01\x01\x01\xFF" }
|
851
|
+
its(:a) { should be_an_instance_of Krypt::ASN1::Sequence }
|
852
|
+
it { subject.a.value.should be_an_instance_of Array }
|
853
|
+
it { subject.a.value.size.should == 2 }
|
854
|
+
it { subject.a.value.all? { |v| v.instance_of?(Krypt::ASN1::Integer) && v.value == 1 }.should == true }
|
855
|
+
its(:b) { should == true }
|
856
|
+
its(:to_der) { should == der }
|
857
|
+
end
|
858
|
+
end
|
859
|
+
|
860
|
+
context "at end" do
|
861
|
+
let(:template) do
|
862
|
+
Class.new do
|
863
|
+
include SEQ
|
864
|
+
asn1_integer :a
|
865
|
+
asn1_any :b
|
866
|
+
end
|
867
|
+
end
|
868
|
+
|
869
|
+
context "as primitive value" do
|
870
|
+
let(:der) { "\x30\x06\x02\x01\x01\x01\x01\xFF" }
|
871
|
+
its(:a) { should == 1 }
|
872
|
+
its(:b) { should be_an_instance_of Krypt::ASN1::Boolean }
|
873
|
+
it { subject.b.value.should == true }
|
874
|
+
its(:to_der) { should == der }
|
875
|
+
end
|
876
|
+
|
877
|
+
context "as sequence" do
|
878
|
+
let(:der) { "\x30\x0B\x02\x01\x02\x30\x06\x02\x01\x01\x02\x01\x01" }
|
879
|
+
its(:a) { should == 2 }
|
880
|
+
its(:b) { should be_an_instance_of Krypt::ASN1::Sequence }
|
881
|
+
it { subject.b.value.should be_an_instance_of Array }
|
882
|
+
it { subject.b.value.size.should == 2 }
|
883
|
+
it { subject.b.value.all? { |v| v.instance_of?(Krypt::ASN1::Integer) && v.value == 1 }.should == true }
|
884
|
+
its(:to_der) { should == der }
|
885
|
+
end
|
886
|
+
end
|
887
|
+
|
888
|
+
context "optionally and tagged between mandatory" do
|
889
|
+
let(:template) do
|
890
|
+
Class.new do
|
891
|
+
include SEQ
|
892
|
+
asn1_integer :a
|
893
|
+
asn1_any :b, tag: 0, tagging: :IMPLICIT, optional: true
|
894
|
+
asn1_boolean :c
|
895
|
+
end
|
896
|
+
end
|
897
|
+
|
898
|
+
context "present" do
|
899
|
+
let(:der) { "\x30\x09\x02\x01\x01\x80\x01a\x01\x01\xFF" }
|
900
|
+
its(:a) { should == 1 }
|
901
|
+
its(:b) { should be_an_instance_of Krypt::ASN1::ASN1Data }
|
902
|
+
it { subject.b.value.should == "a" }
|
903
|
+
it { subject.b.tag.should == 0 }
|
904
|
+
it { subject.b.tag_class.should == :CONTEXT_SPECIFIC }
|
905
|
+
its(:c) { should == true }
|
906
|
+
its(:to_der) { should == der }
|
907
|
+
end
|
908
|
+
|
909
|
+
context "absent" do
|
910
|
+
let(:der) { "\x30\x06\x02\x01\x01\x01\x01\xFF" }
|
911
|
+
its(:a) { should == 1 }
|
912
|
+
its(:b) { should be_nil }
|
913
|
+
its(:c) { should == true }
|
914
|
+
its(:to_der) { should == der }
|
915
|
+
end
|
916
|
+
end
|
917
|
+
|
918
|
+
context "tagged with default" do
|
919
|
+
let(:null) { Krypt::ASN1::Null.new }
|
920
|
+
context
|
921
|
+
let(:template) do
|
922
|
+
n = null
|
923
|
+
Class.new do
|
924
|
+
include SEQ
|
925
|
+
asn1_integer :a
|
926
|
+
asn1_any :b, tag: 0, tagging: :IMPLICIT, default: n
|
927
|
+
asn1_boolean :c
|
928
|
+
end
|
929
|
+
end
|
930
|
+
|
931
|
+
context "present" do
|
932
|
+
let(:der) { "\x30\x09\x02\x01\x01\x80\x01a\x01\x01\xFF" }
|
933
|
+
its(:a) { should == 1 }
|
934
|
+
its(:b) { should be_an_instance_of Krypt::ASN1::ASN1Data }
|
935
|
+
it { subject.b.value.should == "a" }
|
936
|
+
it { subject.b.tag.should == 0 }
|
937
|
+
it { subject.b.tag_class.should == :CONTEXT_SPECIFIC }
|
938
|
+
its(:c) { should == true }
|
939
|
+
its(:to_der) { should == der }
|
940
|
+
end
|
941
|
+
|
942
|
+
context "absent" do
|
943
|
+
let(:der) { "\x30\x06\x02\x01\x01\x01\x01\xFF" }
|
944
|
+
its(:a) { should == 1 }
|
945
|
+
its(:b) { should == null }
|
946
|
+
its(:c) { should == true }
|
947
|
+
its(:to_der) { should == der }
|
948
|
+
end
|
949
|
+
end
|
950
|
+
end
|
951
|
+
|
952
|
+
context "inner CHOICEs" do
|
953
|
+
context "rejects tagging other than :EXPLICIT" do
|
954
|
+
let(:choice) do
|
955
|
+
Class.new do
|
956
|
+
include Krypt::ASN1::Template::Choice
|
957
|
+
asn1_integer
|
958
|
+
end
|
959
|
+
end
|
960
|
+
let(:template) do
|
961
|
+
c = choice
|
962
|
+
tc = tagging
|
963
|
+
Class.new do
|
964
|
+
include SEQ
|
965
|
+
asn1_template :a, c, tag: 0, tagging: tc
|
966
|
+
end
|
967
|
+
end
|
968
|
+
|
969
|
+
context ":IMPLICIT" do
|
970
|
+
let(:tagging) { :IMPLICIT }
|
971
|
+
let(:der) { "\x30\x03\x80\x01\x01" }
|
972
|
+
it { -> { subject.a.value }.should raise_error asn1error }
|
973
|
+
end
|
974
|
+
|
975
|
+
context ":CONTEXT_SPECIFIC" do
|
976
|
+
let(:tagging) { :CONTEXT_SPECIFIC }
|
977
|
+
let(:der) { "\x30\x03\x80\x01\x01" }
|
978
|
+
it { -> { subject.a.value }.should raise_error asn1error }
|
979
|
+
end
|
980
|
+
|
981
|
+
context ":APPLICATION" do
|
982
|
+
let(:tagging) { :APPLICATION }
|
983
|
+
let(:der) { "\x30\x03\x40\x01\x01" }
|
984
|
+
it { -> { subject.a.value }.should raise_error asn1error }
|
985
|
+
end
|
986
|
+
|
987
|
+
context ":PRIVATE" do
|
988
|
+
let(:tagging) { :PRIVATE }
|
989
|
+
let(:der) { "\x30\x03\xC0\x01\x01" }
|
990
|
+
it { -> { subject.a.value }.should raise_error asn1error }
|
991
|
+
end
|
992
|
+
|
993
|
+
#Can be argued. For now, let's not endorse redundancy
|
994
|
+
context ":UNIVERSAL" do
|
995
|
+
let(:tagging) { :UNIVERSAL }
|
996
|
+
let(:der) { "\x30\x03\x02\x01\x01" }
|
997
|
+
it { -> { subject.a.value }.should raise_error asn1error }
|
998
|
+
end
|
999
|
+
|
1000
|
+
context ":EXPLICIT" do
|
1001
|
+
let(:tagging) { :EXPLICIT }
|
1002
|
+
let(:der) { "\x30\x05\xA0\x03\x02\x01\x01" }
|
1003
|
+
it { -> { subject.a.value }.should_not raise_error }
|
1004
|
+
end
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
context "at beginning, primitive choices only" do
|
1008
|
+
let(:choice) do
|
1009
|
+
Class.new do
|
1010
|
+
include Krypt::ASN1::Template::Choice
|
1011
|
+
asn1_integer
|
1012
|
+
asn1_boolean
|
1013
|
+
end
|
1014
|
+
end
|
1015
|
+
let(:template) do
|
1016
|
+
c = choice
|
1017
|
+
Class.new do
|
1018
|
+
include SEQ
|
1019
|
+
asn1_template :a, c
|
1020
|
+
asn1_octet_string :b
|
1021
|
+
end
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
context "match first" do
|
1025
|
+
let(:der) { "\x30\x06\x02\x01\x01\x04\x01a" }
|
1026
|
+
its(:a) { should be_an_instance_of choice }
|
1027
|
+
it { subject.a.type.should == Krypt::ASN1::INTEGER }
|
1028
|
+
it { subject.a.tag.should == Krypt::ASN1::INTEGER }
|
1029
|
+
it { subject.a.value.should == 1 }
|
1030
|
+
its(:b) { should == "a" }
|
1031
|
+
its(:to_der) { should == der }
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
context "match second" do
|
1035
|
+
let(:der) { "\x30\x06\x01\x01\xFF\x04\x01a" }
|
1036
|
+
its(:a) { should be_an_instance_of choice }
|
1037
|
+
it { subject.a.type.should == Krypt::ASN1::BOOLEAN }
|
1038
|
+
it { subject.a.tag.should == Krypt::ASN1::BOOLEAN }
|
1039
|
+
it { subject.a.value.should == true }
|
1040
|
+
its(:b) { should == "a" }
|
1041
|
+
its(:to_der) { should == der }
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
context "with inner tags" do
|
1046
|
+
let(:choice) do
|
1047
|
+
Class.new do
|
1048
|
+
include Krypt::ASN1::Template::Choice
|
1049
|
+
asn1_integer tag: 0, tagging: :IMPLICIT
|
1050
|
+
asn1_boolean tag: 1, tagging: :EXPLICIT
|
1051
|
+
end
|
1052
|
+
end
|
1053
|
+
let(:template) do
|
1054
|
+
c = choice
|
1055
|
+
Class.new do
|
1056
|
+
include SEQ
|
1057
|
+
asn1_template :a, c
|
1058
|
+
asn1_octet_string :b
|
1059
|
+
end
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
context "match first" do
|
1063
|
+
let(:der) { "\x30\x06\x80\x01\x01\x04\x01a" }
|
1064
|
+
its(:a) { should be_an_instance_of choice }
|
1065
|
+
it { subject.a.type.should == Krypt::ASN1::INTEGER }
|
1066
|
+
it { subject.a.tag.should == 0 }
|
1067
|
+
it { subject.a.value.should == 1 }
|
1068
|
+
its(:b) { should == "a" }
|
1069
|
+
its(:to_der) { should == der }
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
context "match second" do
|
1073
|
+
let(:der) { "\x30\x08\xA1\x03\x01\x01\xFF\x04\x01a" }
|
1074
|
+
its(:a) { should be_an_instance_of choice }
|
1075
|
+
it { subject.a.type.should == Krypt::ASN1::BOOLEAN }
|
1076
|
+
it { subject.a.tag.should == 1 }
|
1077
|
+
it { subject.a.value.should == true }
|
1078
|
+
its(:b) { should == "a" }
|
1079
|
+
its(:to_der) { should == der }
|
1080
|
+
end
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
context "primitive choices only, explicitly tagged and default value" do
|
1084
|
+
let(:choice) do
|
1085
|
+
Class.new do
|
1086
|
+
include Krypt::ASN1::Template::Choice
|
1087
|
+
asn1_integer
|
1088
|
+
asn1_boolean
|
1089
|
+
end
|
1090
|
+
end
|
1091
|
+
let(:default_value) do
|
1092
|
+
choice.new do |o|
|
1093
|
+
o.type = Krypt::ASN1::INTEGER
|
1094
|
+
o.value = 42
|
1095
|
+
end
|
1096
|
+
end
|
1097
|
+
let(:template) do
|
1098
|
+
c = choice
|
1099
|
+
v = default_value
|
1100
|
+
Class.new do
|
1101
|
+
include SEQ
|
1102
|
+
asn1_template :a, c, tag: 0, tagging: :EXPLICIT, default: v
|
1103
|
+
asn1_octet_string :b
|
1104
|
+
end
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
context "present, match first" do
|
1108
|
+
let(:der) { "\x30\x08\xA0\x03\x02\x01\x01\x04\x01a" }
|
1109
|
+
its(:a) { should be_an_instance_of choice }
|
1110
|
+
it { subject.a.type.should == Krypt::ASN1::INTEGER }
|
1111
|
+
it { subject.a.tag.should == 2 } # it's the tag within the choice, the outer tag doesn't matter
|
1112
|
+
it { subject.a.value.should == 1 }
|
1113
|
+
its(:b) { should == "a" }
|
1114
|
+
its(:to_der) { should == der }
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
context "present, match second" do
|
1118
|
+
let(:der) { "\x30\x08\xA0\x03\x01\x01\xFF\x04\x01a" }
|
1119
|
+
its(:a) { should be_an_instance_of choice }
|
1120
|
+
it { subject.a.type.should == Krypt::ASN1::BOOLEAN }
|
1121
|
+
it { subject.a.tag.should == 1 } # it's the tag within the choice, the outer tag doesn't matter
|
1122
|
+
it { subject.a.value.should == true }
|
1123
|
+
its(:b) { should == "a" }
|
1124
|
+
its(:to_der) { should == der }
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
context "absent" do
|
1128
|
+
let(:der) { "\x30\x03\x04\x01a" }
|
1129
|
+
its(:a) { should == default_value }
|
1130
|
+
its(:b) { should == "a" }
|
1131
|
+
its(:to_der) { should == der }
|
1132
|
+
end
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
context "with inner tagged templates, while outer CHOICE is explicitly tagged" do
|
1136
|
+
let(:template2) do
|
1137
|
+
Class.new do
|
1138
|
+
include Krypt::ASN1::Template::Sequence
|
1139
|
+
asn1_integer :a
|
1140
|
+
end
|
1141
|
+
end
|
1142
|
+
let(:template3) do
|
1143
|
+
Class.new do
|
1144
|
+
include Krypt::ASN1::Template::Sequence
|
1145
|
+
asn1_boolean :a
|
1146
|
+
end
|
1147
|
+
end
|
1148
|
+
let(:choice) do
|
1149
|
+
t2 = template2
|
1150
|
+
t3 = template3
|
1151
|
+
Class.new do
|
1152
|
+
include Krypt::ASN1::Template::Choice
|
1153
|
+
asn1_template t2, tag: 0, tagging: :IMPLICIT
|
1154
|
+
asn1_template t3, tag: 1, tagging: :EXPLICIT
|
1155
|
+
end
|
1156
|
+
end
|
1157
|
+
let(:template) do
|
1158
|
+
c = choice
|
1159
|
+
Class.new do
|
1160
|
+
include SEQ
|
1161
|
+
asn1_integer :a
|
1162
|
+
asn1_template :b, c, tag: 2, tagging: :EXPLICIT
|
1163
|
+
end
|
1164
|
+
end
|
1165
|
+
|
1166
|
+
context "match first" do
|
1167
|
+
let(:der) { "\x30\x0A\x02\x01\x01\xA2\x05\xA0\x03\x02\x01\x01" }
|
1168
|
+
its(:a) { should == 1 }
|
1169
|
+
its(:b) { should be_an_instance_of choice }
|
1170
|
+
it { subject.b.type.should == template2 }
|
1171
|
+
it { subject.b.tag.should == 0 } # it's the tag within the choice, the outer tag doesn't matter
|
1172
|
+
it { subject.b.value.should be_an_instance_of template2 }
|
1173
|
+
it { subject.b.value.a.should == 1 }
|
1174
|
+
its(:to_der) { should == der }
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
context "match second" do
|
1178
|
+
let(:der) { "\x30\x0C\x02\x01\x01\xA2\x07\xA1\x05\x30\x03\x01\x01\xFF" }
|
1179
|
+
its(:a) { should == 1 }
|
1180
|
+
its(:b) { should be_an_instance_of choice }
|
1181
|
+
it { subject.b.type.should == template3 }
|
1182
|
+
it { subject.b.tag.should == 1 } # it's the tag within the choice, the outer tag doesn't matter
|
1183
|
+
it { subject.b.value.should be_an_instance_of template3 }
|
1184
|
+
it { subject.b.value.a.should == true }
|
1185
|
+
its(:to_der) { should == der }
|
1186
|
+
end
|
1187
|
+
end
|
1188
|
+
|
1189
|
+
context "integer and SEQUENCE OF template" do
|
1190
|
+
let(:template2) do
|
1191
|
+
Class.new do
|
1192
|
+
include Krypt::ASN1::Template::Sequence
|
1193
|
+
asn1_integer :a
|
1194
|
+
end
|
1195
|
+
end
|
1196
|
+
let(:seqof) do
|
1197
|
+
t2 = template2
|
1198
|
+
Class.new do
|
1199
|
+
include Krypt::ASN1::Template::SequenceOf
|
1200
|
+
asn1_type t2
|
1201
|
+
end
|
1202
|
+
end
|
1203
|
+
let(:choice) do
|
1204
|
+
sof = seqof
|
1205
|
+
Class.new do
|
1206
|
+
include Krypt::ASN1::Template::Choice
|
1207
|
+
asn1_integer
|
1208
|
+
asn1_template sof
|
1209
|
+
end
|
1210
|
+
end
|
1211
|
+
let(:template) do
|
1212
|
+
c = choice
|
1213
|
+
Class.new do
|
1214
|
+
include SEQ
|
1215
|
+
asn1_template :a, c
|
1216
|
+
end
|
1217
|
+
end
|
1218
|
+
|
1219
|
+
context "match integer" do
|
1220
|
+
let(:der) { "\x30\x03\x02\x01\x01" }
|
1221
|
+
its(:a) { should be_an_instance_of choice }
|
1222
|
+
it { subject.a.tag.should == Krypt::ASN1::INTEGER }
|
1223
|
+
it { subject.a.type.should == Krypt::ASN1::INTEGER }
|
1224
|
+
it { subject.a.value.should == 1 }
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
context "match SEQUENCE OF template" do
|
1228
|
+
let(:der) { "\x30\x0C\x30\x0A\x30\x03\x02\x01\x01\x30\x03\x02\x01\x01" }
|
1229
|
+
its(:a) { should be_an_instance_of choice }
|
1230
|
+
it { subject.a.tag.should == Krypt::ASN1::SEQUENCE }
|
1231
|
+
it { subject.a.type.should == seqof }
|
1232
|
+
it { subject.a.value.should be_an_instance_of seqof }
|
1233
|
+
it { subject.a.value.value.should be_an_instance_of Array }
|
1234
|
+
it { subject.a.value.value.size.should == 2 }
|
1235
|
+
it { subject.a.value.value.all? { |v| v.instance_of?(template2) && v.a == 1 }.should == true }
|
1236
|
+
end
|
1237
|
+
end
|
1238
|
+
end
|
1239
|
+
end
|
1240
|
+
end
|
1241
|
+
|