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