krypt 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,102 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'krypt'
|
3
|
+
|
4
|
+
describe Krypt::Hex do
|
5
|
+
|
6
|
+
let(:mod) { Krypt::Hex }
|
7
|
+
|
8
|
+
describe "encode" do
|
9
|
+
context "single parameter data" do
|
10
|
+
context "RFC 4648 test vectors" do
|
11
|
+
specify "empty string" do
|
12
|
+
mod.encode("").should == ""
|
13
|
+
end
|
14
|
+
|
15
|
+
specify "f" do
|
16
|
+
mod.encode("f").should == "66"
|
17
|
+
end
|
18
|
+
|
19
|
+
specify "fo" do
|
20
|
+
mod.encode("fo").should == "666f"
|
21
|
+
end
|
22
|
+
|
23
|
+
specify "foo" do
|
24
|
+
mod.encode("foo").should == "666f6f"
|
25
|
+
end
|
26
|
+
|
27
|
+
specify "foob" do
|
28
|
+
mod.encode("foob").should == "666f6f62"
|
29
|
+
end
|
30
|
+
|
31
|
+
specify "fooba" do
|
32
|
+
mod.encode("fooba").should == "666f6f6261"
|
33
|
+
end
|
34
|
+
|
35
|
+
specify "foobar" do
|
36
|
+
mod.encode("foobar").should == "666f6f626172"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should return a string with US-ASCII encoding" do
|
42
|
+
mod.encode("test").encoding.should == Encoding::US_ASCII
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return a string with US-ASCII encoding even if
|
46
|
+
the underlying encoding is not" do
|
47
|
+
auml = [%w{ C3 A4 }.join('')].pack('H*')
|
48
|
+
auml.force_encoding(Encoding::UTF_8)
|
49
|
+
mod.encode(auml).encoding.should == Encoding::US_ASCII
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "decode" do
|
54
|
+
context "RFC 4648 test vectors" do
|
55
|
+
specify "empty string" do
|
56
|
+
mod.decode("").should == ""
|
57
|
+
end
|
58
|
+
|
59
|
+
specify "f" do
|
60
|
+
mod.decode("66").should == "f"
|
61
|
+
end
|
62
|
+
|
63
|
+
specify "fo" do
|
64
|
+
mod.decode("666f").should == "fo"
|
65
|
+
end
|
66
|
+
|
67
|
+
specify "foo" do
|
68
|
+
mod.decode("666f6f").should == "foo"
|
69
|
+
end
|
70
|
+
|
71
|
+
specify "foob" do
|
72
|
+
mod.decode("666f6f62").should == "foob"
|
73
|
+
end
|
74
|
+
|
75
|
+
specify "fooba" do
|
76
|
+
mod.decode("666f6f6261").should == "fooba"
|
77
|
+
end
|
78
|
+
|
79
|
+
specify "foobar" do
|
80
|
+
mod.decode("666f6f626172").should == "foobar"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should return a string with binary encoding" do
|
85
|
+
mod.decode("666f6f626172").encoding.should == Encoding::BINARY
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should return a string with US-ASCII encoding even if
|
89
|
+
the underlying encoding is not" do
|
90
|
+
data = "666f"
|
91
|
+
data.force_encoding(Encoding::UTF_8)
|
92
|
+
mod.decode(data).encoding.should == Encoding::BINARY
|
93
|
+
end
|
94
|
+
|
95
|
+
it "ignores case for a-f" do
|
96
|
+
str = "666f6f626172"
|
97
|
+
dec = "foobar"
|
98
|
+
mod.decode(str).should == dec
|
99
|
+
mod.decode(str.upcase).should == dec
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,235 @@
|
|
1
|
+
# encoding: US-ASCII
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'krypt'
|
5
|
+
require 'stringio'
|
6
|
+
require 'base64'
|
7
|
+
require_relative '../resources'
|
8
|
+
|
9
|
+
describe Krypt::PEM do
|
10
|
+
let(:mod) { Krypt::PEM }
|
11
|
+
let(:pemerror) { Krypt::PEM::PEMError }
|
12
|
+
let(:intb64) { ::Base64.encode64("\x02\x01\x01") }
|
13
|
+
|
14
|
+
def create_pem_b64(b64, name)
|
15
|
+
"-----BEGIN #{name}-----\n#{b64}-----END #{name}-----\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "PEM.decode" do
|
19
|
+
subject { mod.decode(value) }
|
20
|
+
|
21
|
+
context "returns an Array" do
|
22
|
+
let(:value) { Resources.certificate_pem }
|
23
|
+
it { should be_an_instance_of(Array) }
|
24
|
+
end
|
25
|
+
|
26
|
+
context"decodes Strings" do
|
27
|
+
context "decodes a single PEM value" do
|
28
|
+
let(:value) { Resources.certificate_pem }
|
29
|
+
its(:size) { should == 1 }
|
30
|
+
it { subject[0].should == Resources.certificate }
|
31
|
+
end
|
32
|
+
|
33
|
+
context "decodes multiple PEM values" do
|
34
|
+
let(:value) { Resources.certificate_pem * 3 }
|
35
|
+
its(:size) { should == 3 }
|
36
|
+
it { subject.all? { |der| der == Resources.certificate }.should be_true }
|
37
|
+
end
|
38
|
+
|
39
|
+
context "decodes multiple mixed PEM values" do
|
40
|
+
let(:value) { Resources.certificate_pem + create_pem_b64(intb64, "INTEGER") }
|
41
|
+
its(:size) { should == 2 }
|
42
|
+
it do
|
43
|
+
subject[0].should == Resources.certificate
|
44
|
+
subject[1].should == "\x02\x01\x01"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "decodes long PEM values" do
|
49
|
+
let(:der) { "\x04\x82\x4E\x20" + "\x01" * 20_000 }
|
50
|
+
let(:value) { create_pem_b64("#{::Base64.encode64(der)}", "OCTET STRING") }
|
51
|
+
its(:size) { should == 1 }
|
52
|
+
it { subject[0].should == der }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "decodes StringIO" do
|
57
|
+
context "decodes a single PEM value" do
|
58
|
+
let(:value) { StringIO.new(Resources.certificate_pem) }
|
59
|
+
its(:size) { should == 1 }
|
60
|
+
it { subject[0].should == Resources.certificate }
|
61
|
+
end
|
62
|
+
|
63
|
+
context "decodes multiple PEM values" do
|
64
|
+
let(:value) { StringIO.new(Resources.certificate_pem * 3) }
|
65
|
+
its(:size) { should == 3 }
|
66
|
+
it { subject.all? { |der| der == Resources.certificate }.should be_true }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "decodes Files" do
|
71
|
+
subject do
|
72
|
+
begin
|
73
|
+
mod.decode(io)
|
74
|
+
ensure
|
75
|
+
io.close
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "decodes a File containing a single PEM value" do
|
80
|
+
let(:io) { Resources.certificate_pem_io }
|
81
|
+
its(:size) { should == 1 }
|
82
|
+
it { subject[0].should == Resources.certificate }
|
83
|
+
end
|
84
|
+
|
85
|
+
context "decodes a File containing multiple PEM values" do
|
86
|
+
let(:io) { Resources.multi_certificate_pem_io }
|
87
|
+
its(:size) { should == 3 }
|
88
|
+
it { subject.all? { |der| der == Resources.certificate }.should be_true }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "decodes arbitrary objects that respond to to_pem" do
|
93
|
+
let(:value) do
|
94
|
+
o = Object.new
|
95
|
+
def o.to_pem
|
96
|
+
Resources.certificate_pem
|
97
|
+
end
|
98
|
+
o
|
99
|
+
end
|
100
|
+
its(:size) { should == 1 }
|
101
|
+
it { subject[0].should == Resources.certificate }
|
102
|
+
end
|
103
|
+
|
104
|
+
context "does not require terminating line break" do
|
105
|
+
let(:value) { "-----BEGIN ABC-----\n#{intb64}-----END ABC-----" }
|
106
|
+
its(:size) { should == 1 }
|
107
|
+
it { subject[0].should == "\x02\x01\x01" }
|
108
|
+
end
|
109
|
+
|
110
|
+
context "ignores empty lines" do
|
111
|
+
context "LF" do
|
112
|
+
let(:value) { "\n" + create_pem_b64("\n#{intb64}\n", "INTEGER") + "\n" }
|
113
|
+
its(:size) { should == 1 }
|
114
|
+
it { subject[0].should == "\x02\x01\x01" }
|
115
|
+
end
|
116
|
+
|
117
|
+
context "CRLF" do
|
118
|
+
let(:value) { "\r\n" + create_pem_b64("\r\n#{intb64}\r\n", "INTEGER") + "\r\n" }
|
119
|
+
its(:size) { should == 1 }
|
120
|
+
it { subject[0].should == "\x02\x01\x01" }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "normalizes CRLF and LF" do
|
125
|
+
context "LF only" do
|
126
|
+
let(:value) { "-----BEGIN A-----\n#{intb64}-----END A-----\n" }
|
127
|
+
it { subject[0].should == "\x02\x01\x01" }
|
128
|
+
end
|
129
|
+
|
130
|
+
context "CRLF only" do
|
131
|
+
let(:value) { "-----BEGIN A-----\r\n#{::Base64.encode64("\x02\x01\x01")}\r\n-----END A-----\r\n" }
|
132
|
+
it { subject[0].should == "\x02\x01\x01" }
|
133
|
+
end
|
134
|
+
|
135
|
+
context "mixed: CRLF header, LF footer" do
|
136
|
+
let(:value) { "-----BEGIN A-----\r\n#{intb64}-----END A-----\n" }
|
137
|
+
it { subject[0].should == "\x02\x01\x01" }
|
138
|
+
end
|
139
|
+
|
140
|
+
context "mixed: LF header, CRLF footer" do
|
141
|
+
let(:value) { "-----BEGIN A-----\n#{intb64}-----END A-----\r\n" }
|
142
|
+
it { subject[0].should == "\x02\x01\x01" }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context "allows arbitrary content between PEM blocks" do
|
147
|
+
context "String with LF as last character" do
|
148
|
+
let(:value) { "Next up a certificate.\n#{Resources.certificate_pem}After the certificate\n" }
|
149
|
+
its(:size) { should == 1 }
|
150
|
+
it { subject[0].should == Resources.certificate }
|
151
|
+
end
|
152
|
+
|
153
|
+
context "String not ending in LF as last character" do
|
154
|
+
let(:value) { "Next up a certificate.\n#{Resources.certificate_pem}After the certificate" }
|
155
|
+
its(:size) { should == 1 }
|
156
|
+
it { subject[0].should == Resources.certificate }
|
157
|
+
end
|
158
|
+
|
159
|
+
context "File containing a 'CA certificate bundle'" do
|
160
|
+
let(:value) { Resources.ca_certificate_pem_io }
|
161
|
+
its(:size) { should == 136 }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context "rejects values with non-matching names" do
|
166
|
+
let(:value) { "-----BEGIN A-----\n#{intb64}-----END B-----" }
|
167
|
+
it { -> { subject }.should raise_error pemerror }
|
168
|
+
end
|
169
|
+
|
170
|
+
context "allows no redundant whitespace" do
|
171
|
+
context"leading in header" do
|
172
|
+
let(:value) { " -----BEGIN A-----\n#{intb64}-----END A-----" }
|
173
|
+
it { subject.should be_empty }
|
174
|
+
end
|
175
|
+
|
176
|
+
context"leading in footer" do
|
177
|
+
let(:value) { "-----BEGIN A-----\n#{intb64} -----END A-----" }
|
178
|
+
it { -> { subject }.should raise_error pemerror }
|
179
|
+
end
|
180
|
+
|
181
|
+
context"trailing in header" do
|
182
|
+
let(:value) { "-----BEGIN A----- \n#{intb64}-----END A-----" }
|
183
|
+
it { subject.should be_empty }
|
184
|
+
end
|
185
|
+
|
186
|
+
context"trailing in footer" do
|
187
|
+
let(:value) { "-----BEGIN A-----\n#{intb64}-----END A----- " }
|
188
|
+
it { -> { subject }.should raise_error pemerror }
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context "does not expect line breaks for Base64 content" do
|
193
|
+
context "in small data" do
|
194
|
+
let(:der) { "\x04\x82\x03\xE8" + "\x01" * 80 }
|
195
|
+
let(:value) { "-----BEGIN ABC-----\n#{::Base64.strict_encode64(der)}\n-----END ABC-----" }
|
196
|
+
it { subject[0].should == der }
|
197
|
+
end
|
198
|
+
|
199
|
+
context "in large data" do
|
200
|
+
let(:der) { "\x04\x82\x4E\x20" + "\x01" * 20_000 }
|
201
|
+
let(:value) { "-----BEGIN ABC-----\n#{::Base64.strict_encode64(der)}\n-----END ABC-----" }
|
202
|
+
it { subject[0].should == der }
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context "takes a block" do
|
207
|
+
context "whose first argument is the current value" do
|
208
|
+
let(:value) { Resources.certificate_pem * 3 }
|
209
|
+
it do
|
210
|
+
ary = []
|
211
|
+
cmp = mod.decode(value) { |asn1| ary << asn1 }
|
212
|
+
ary.should == cmp
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
context "whose second argument is the name of the current value" do
|
217
|
+
let(:value) { Resources.certificate_pem * 3 }
|
218
|
+
it do
|
219
|
+
ary = []
|
220
|
+
mod.decode(value) { |asn1, name| ary << name }
|
221
|
+
ary.should == ["CERTIFICATE", "CERTIFICATE", "CERTIFICATE"]
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
context "whose third argument is the current index, starting at 0" do
|
226
|
+
let(:value) { Resources.certificate_pem * 3 }
|
227
|
+
it do
|
228
|
+
ary = []
|
229
|
+
mod.decode(value) { |asn1, name, i| ary << i }
|
230
|
+
ary.should == [0,1,2]
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative '../resources'
|
@@ -0,0 +1,289 @@
|
|
1
|
+
# encoding: US-ASCII
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'krypt'
|
5
|
+
require_relative '../resources'
|
6
|
+
|
7
|
+
describe "Krypt::ASN1::Template::Choice" do
|
8
|
+
CHOICE = Krypt::ASN1::Template::Choice
|
9
|
+
let(:asn1error) { Krypt::ASN1::ASN1Error }
|
10
|
+
|
11
|
+
context "extracted from parse_der" do
|
12
|
+
subject { template.parse_der(der) }
|
13
|
+
|
14
|
+
context "single field" do
|
15
|
+
let(:template) do
|
16
|
+
Class.new do
|
17
|
+
include CHOICE
|
18
|
+
asn1_integer
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "accepts correct encoding" do
|
23
|
+
let(:der) { "\x02\x01\x01" }
|
24
|
+
its(:value) { should == 1 }
|
25
|
+
it { subject.type.should == Krypt::ASN1::INTEGER }
|
26
|
+
it { subject.tag.should == Krypt::ASN1::INTEGER }
|
27
|
+
it { subject.should be_an_instance_of template }
|
28
|
+
its(:to_der) { should == der }
|
29
|
+
end
|
30
|
+
|
31
|
+
context "rejects wrong encoding" do
|
32
|
+
let(:der) { "\x04\x01\x01" }
|
33
|
+
it { -> { subject.value }.should raise_error asn1error }
|
34
|
+
end
|
35
|
+
|
36
|
+
context "rejects encoding that is not complete" do
|
37
|
+
let(:der) { "\x02\x01" }
|
38
|
+
it { -> { subject.value }.should raise_error asn1error }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "two fields" do
|
43
|
+
let(:template) do
|
44
|
+
Class.new do
|
45
|
+
include CHOICE
|
46
|
+
asn1_integer
|
47
|
+
asn1_boolean
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "accepts correct encoding integer" do
|
52
|
+
let(:der) { "\x02\x01\x01" }
|
53
|
+
its(:value) { should == 1 }
|
54
|
+
its(:type) { should == Krypt::ASN1::INTEGER }
|
55
|
+
its(:tag) { should == Krypt::ASN1::INTEGER }
|
56
|
+
it { subject.should be_an_instance_of template }
|
57
|
+
its(:to_der) { should == der }
|
58
|
+
end
|
59
|
+
|
60
|
+
context "accepts correct encoding boolean" do
|
61
|
+
let(:der) { "\x01\x01\xFF" }
|
62
|
+
its(:value) { should == true }
|
63
|
+
its(:type) { should == Krypt::ASN1::BOOLEAN }
|
64
|
+
its(:tag) { should == Krypt::ASN1::BOOLEAN }
|
65
|
+
it { subject.should be_an_instance_of template }
|
66
|
+
its(:to_der) { should == der }
|
67
|
+
end
|
68
|
+
|
69
|
+
context "rejects wrong encoding" do
|
70
|
+
let(:der) { "\x04\x01\xFF" }
|
71
|
+
it { -> { subject.value }.should raise_error asn1error }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "preserves non-DER encodings" do
|
76
|
+
let(:template) do
|
77
|
+
Class.new do
|
78
|
+
include CHOICE
|
79
|
+
asn1_boolean
|
80
|
+
end
|
81
|
+
end
|
82
|
+
let(:der) { "\x01\x83\x00\x00\x01\x22" }
|
83
|
+
its(:to_der) { should == der }
|
84
|
+
end
|
85
|
+
|
86
|
+
context "does not choke on invalid encodings" do
|
87
|
+
let(:template) do
|
88
|
+
Class.new do
|
89
|
+
include CHOICE
|
90
|
+
asn1_integer
|
91
|
+
asn1_octet_string
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "when parsing them" do
|
96
|
+
let(:der) { "\x02\x00" }
|
97
|
+
it { -> { subject }.should_not raise_error }
|
98
|
+
end
|
99
|
+
|
100
|
+
context "and encodes them again exactly as received" do
|
101
|
+
let(:der) { "\x02\x00" }
|
102
|
+
its(:to_der) { should == der }
|
103
|
+
end
|
104
|
+
|
105
|
+
context "but raises an error when accessing the fields" do
|
106
|
+
let(:der) { "\x02\x00" }
|
107
|
+
it { -> { subject.value }.should raise_error asn1error }
|
108
|
+
end
|
109
|
+
|
110
|
+
context "but raises an error if the tag does not match" do
|
111
|
+
let(:der) { "\x01\x01\xFF" }
|
112
|
+
it { -> { subject.value }.should raise_error asn1error }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "with inner templates" do
|
117
|
+
let(:template2) do
|
118
|
+
Class.new do
|
119
|
+
include Krypt::ASN1::Template::Sequence
|
120
|
+
asn1_integer :a
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "no further options" do
|
125
|
+
let(:template) do
|
126
|
+
t = template2
|
127
|
+
Class.new do
|
128
|
+
include CHOICE
|
129
|
+
asn1_template t
|
130
|
+
end
|
131
|
+
end
|
132
|
+
let(:der) { "\x30\x03\x02\x01\x01" }
|
133
|
+
its(:value) { should be_an_instance_of template2 }
|
134
|
+
its(:tag) { should == Krypt::ASN1::SEQUENCE }
|
135
|
+
its(:type) { should == template2 }
|
136
|
+
it { subject.value.a.should == 1 }
|
137
|
+
end
|
138
|
+
|
139
|
+
context "with implicit tags" do
|
140
|
+
let(:template3) do
|
141
|
+
Class.new do
|
142
|
+
include Krypt::ASN1::Template::Sequence
|
143
|
+
asn1_boolean :a
|
144
|
+
end
|
145
|
+
end
|
146
|
+
let(:template) do
|
147
|
+
t2 = template2
|
148
|
+
t3 = template3
|
149
|
+
Class.new do
|
150
|
+
include CHOICE
|
151
|
+
asn1_template t2, tag: 0, tagging: :IMPLICIT
|
152
|
+
asn1_template t3, tag: 1, tagging: :IMPLICIT
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "matches first" do
|
157
|
+
let(:der) { "\xA0\x03\x02\x01\x01" }
|
158
|
+
its(:value) { should be_an_instance_of template2 }
|
159
|
+
its(:tag) { should == 0 }
|
160
|
+
its(:type) { should == template2 }
|
161
|
+
it { subject.value.a.should == 1 }
|
162
|
+
end
|
163
|
+
|
164
|
+
context "matches second" do
|
165
|
+
let(:der) { "\xA1\x03\x01\x01\xFF" }
|
166
|
+
its(:value) { should be_an_instance_of template3 }
|
167
|
+
its(:tag) { should == 1 }
|
168
|
+
its(:type) { should == template3 }
|
169
|
+
it { subject.value.a.should == true }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context "with explicit tags" do
|
174
|
+
let(:template3) do
|
175
|
+
Class.new do
|
176
|
+
include Krypt::ASN1::Template::Sequence
|
177
|
+
asn1_boolean :a
|
178
|
+
end
|
179
|
+
end
|
180
|
+
let(:template) do
|
181
|
+
t2 = template2
|
182
|
+
t3 = template3
|
183
|
+
Class.new do
|
184
|
+
include CHOICE
|
185
|
+
asn1_template t2, tag: 0, tagging: :EXPLICIT
|
186
|
+
asn1_template t3, tag: 1, tagging: :EXPLICIT
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
context "matches first" do
|
191
|
+
let(:der) { "\xA0\x05\x30\x03\x02\x01\x01" }
|
192
|
+
its(:value) { should be_an_instance_of template2 }
|
193
|
+
its(:tag) { should == 0 }
|
194
|
+
its(:type) { should == template2 }
|
195
|
+
it { subject.value.a.should == 1 }
|
196
|
+
end
|
197
|
+
|
198
|
+
context "matches second" do
|
199
|
+
let(:der) { "\xA1\x05\x30\x03\x01\x01\xFF" }
|
200
|
+
its(:value) { should be_an_instance_of template3 }
|
201
|
+
its(:tag) { should == 1 }
|
202
|
+
its(:type) { should == template3 }
|
203
|
+
it { subject.value.a.should == true }
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context "with SEQUENCE OF" do
|
208
|
+
let(:template) do
|
209
|
+
t2 = template2
|
210
|
+
Class.new do
|
211
|
+
include CHOICE
|
212
|
+
asn1_sequence_of t2
|
213
|
+
end
|
214
|
+
end
|
215
|
+
let(:der) { "\x30\x0A\x30\x03\x02\x01\x01\x30\x03\x02\x01\x01" }
|
216
|
+
its(:value) { should be_an_instance_of Array }
|
217
|
+
its(:type) { should == template2 }
|
218
|
+
its(:tag) { should == Krypt::ASN1::SEQUENCE }
|
219
|
+
it { subject.value.size.should == 2 }
|
220
|
+
it { subject.value.all? { |v| v.instance_of?(template2) && v.a == 1 }.should == true }
|
221
|
+
its(:to_der) { should == der }
|
222
|
+
end
|
223
|
+
|
224
|
+
context "with SET OF" do
|
225
|
+
let(:template) do
|
226
|
+
t2 = template2
|
227
|
+
Class.new do
|
228
|
+
include CHOICE
|
229
|
+
asn1_set_of t2
|
230
|
+
end
|
231
|
+
end
|
232
|
+
let(:der) { "\x31\x0A\x30\x03\x02\x01\x01\x30\x03\x02\x01\x01" }
|
233
|
+
its(:value) { should be_an_instance_of Array }
|
234
|
+
its(:type) { should == template2 }
|
235
|
+
its(:tag) { should == Krypt::ASN1::SET }
|
236
|
+
it { subject.value.size.should == 2 }
|
237
|
+
it { subject.value.all? { |v| v.instance_of?(template2) && v.a == 1 }.should == true }
|
238
|
+
its(:to_der) { should == der }
|
239
|
+
end
|
240
|
+
|
241
|
+
context "with ANY" do
|
242
|
+
context "alone" do
|
243
|
+
let(:template) do
|
244
|
+
t2 = template2
|
245
|
+
Class.new do
|
246
|
+
include CHOICE
|
247
|
+
asn1_any
|
248
|
+
end
|
249
|
+
end
|
250
|
+
let(:der) { "\x02\x01\x01" }
|
251
|
+
its(:value) { should be_an_instance_of Krypt::ASN1::Integer }
|
252
|
+
its(:type) { should == Krypt::ASN1::ASN1Data }
|
253
|
+
its(:tag) { should == Krypt::ASN1::INTEGER }
|
254
|
+
it { subject.value.value.should == 1 }
|
255
|
+
its(:to_der) { should == der }
|
256
|
+
end
|
257
|
+
|
258
|
+
context "the first ANY field matches if no other will" do
|
259
|
+
let(:template) do
|
260
|
+
t2 = template2
|
261
|
+
Class.new do
|
262
|
+
include CHOICE
|
263
|
+
asn1_integer
|
264
|
+
asn1_any
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
context "other matches" do
|
269
|
+
let(:der) { "\x02\x01\x01" }
|
270
|
+
its(:value) { should == 1 }
|
271
|
+
its(:type) { should == Krypt::ASN1::INTEGER }
|
272
|
+
its(:tag) { should == Krypt::ASN1::INTEGER }
|
273
|
+
its(:to_der) { should == der }
|
274
|
+
end
|
275
|
+
|
276
|
+
context "ANY matches" do
|
277
|
+
let(:der) { "\x01\x01\xFF" }
|
278
|
+
its(:value) { should be_an_instance_of Krypt::ASN1::Boolean }
|
279
|
+
its(:type) { should == Krypt::ASN1::ASN1Data }
|
280
|
+
its(:tag) { should == Krypt::ASN1::BOOLEAN }
|
281
|
+
it { subject.value.value.should == true }
|
282
|
+
its(:to_der) { should == der }
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|