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.
Files changed (70) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +82 -0
  3. data/lib/krypt.rb +49 -0
  4. data/lib/krypt/asn1.rb +3 -0
  5. data/lib/krypt/asn1/common.rb +96 -0
  6. data/lib/krypt/asn1/template.rb +257 -0
  7. data/lib/krypt/codec.rb +57 -0
  8. data/lib/krypt/codec/base64.rb +140 -0
  9. data/lib/krypt/codec/base_codec.rb +36 -0
  10. data/lib/krypt/codec/hex.rb +122 -0
  11. data/lib/krypt/digest.rb +112 -0
  12. data/lib/krypt/hmac.rb +69 -0
  13. data/lib/krypt/pkcs5.rb +1 -0
  14. data/lib/krypt/pkcs5/pbkdf2.rb +41 -0
  15. data/lib/krypt/provider.rb +35 -0
  16. data/lib/krypt/x509.rb +3 -0
  17. data/lib/krypt/x509/certificate.rb +36 -0
  18. data/lib/krypt/x509/common.rb +41 -0
  19. data/lib/krypt/x509/crl.rb +33 -0
  20. data/lib/krypt_missing.rb +32 -0
  21. data/spec/krypt-core/MEMO.txt +85 -0
  22. data/spec/krypt-core/asn1/asn1_bit_string_spec.rb +475 -0
  23. data/spec/krypt-core/asn1/asn1_boolean_spec.rb +392 -0
  24. data/spec/krypt-core/asn1/asn1_constants_spec.rb +71 -0
  25. data/spec/krypt-core/asn1/asn1_data_spec.rb +1153 -0
  26. data/spec/krypt-core/asn1/asn1_end_of_contents_spec.rb +133 -0
  27. data/spec/krypt-core/asn1/asn1_enumerated_spec.rb +458 -0
  28. data/spec/krypt-core/asn1/asn1_generalized_time_spec.rb +492 -0
  29. data/spec/krypt-core/asn1/asn1_integer_spec.rb +557 -0
  30. data/spec/krypt-core/asn1/asn1_null_spec.rb +360 -0
  31. data/spec/krypt-core/asn1/asn1_object_id_spec.rb +495 -0
  32. data/spec/krypt-core/asn1/asn1_octet_string_spec.rb +456 -0
  33. data/spec/krypt-core/asn1/asn1_parser_spec.rb +503 -0
  34. data/spec/krypt-core/asn1/asn1_pem_spec.rb +282 -0
  35. data/spec/krypt-core/asn1/asn1_sequence_spec.rb +637 -0
  36. data/spec/krypt-core/asn1/asn1_set_spec.rb +795 -0
  37. data/spec/krypt-core/asn1/asn1_utc_time_spec.rb +495 -0
  38. data/spec/krypt-core/asn1/asn1_utf8_string_spec.rb +404 -0
  39. data/spec/krypt-core/asn1/resources.rb +53 -0
  40. data/spec/krypt-core/base64/base64_spec.rb +97 -0
  41. data/spec/krypt-core/digest/digest_spec.rb +707 -0
  42. data/spec/krypt-core/hex/hex_spec.rb +102 -0
  43. data/spec/krypt-core/pem/pem_decode_spec.rb +235 -0
  44. data/spec/krypt-core/resources.rb +1 -0
  45. data/spec/krypt-core/template/template_choice_parse_spec.rb +289 -0
  46. data/spec/krypt-core/template/template_dsl_spec.rb +351 -0
  47. data/spec/krypt-core/template/template_seq_of_parse_spec.rb +64 -0
  48. data/spec/krypt-core/template/template_seq_parse_spec.rb +1241 -0
  49. data/spec/krypt/codec/base64_decoder_spec.rb +94 -0
  50. data/spec/krypt/codec/base64_encoder_spec.rb +94 -0
  51. data/spec/krypt/codec/base64_mixed_spec.rb +16 -0
  52. data/spec/krypt/codec/hex_decoder_spec.rb +94 -0
  53. data/spec/krypt/codec/hex_encoder_spec.rb +94 -0
  54. data/spec/krypt/codec/hex_mixed_spec.rb +17 -0
  55. data/spec/krypt/codec/identity_shared.rb +119 -0
  56. data/spec/krypt/hmac/hmac_spec.rb +311 -0
  57. data/spec/krypt/pkcs5/pbkdf2_spec.rb +79 -0
  58. data/spec/krypt/provider/provider_spec.rb +83 -0
  59. data/spec/res/ca-bundle.crt +11758 -0
  60. data/spec/res/certificate.cer +0 -0
  61. data/spec/res/certificate.pem +20 -0
  62. data/spec/res/multiple_certs.pem +60 -0
  63. data/spec/resources.rb +66 -0
  64. data/test/helper.rb +8 -0
  65. data/test/res/certificate.cer +0 -0
  66. data/test/resources.rb +48 -0
  67. data/test/scratch.rb +28 -0
  68. data/test/test_krypt_asn1.rb +119 -0
  69. data/test/test_krypt_parser.rb +331 -0
  70. metadata +134 -0
@@ -0,0 +1,360 @@
1
+ # encoding: US-ASCII
2
+
3
+ require 'rspec'
4
+ require 'krypt'
5
+ require 'openssl'
6
+ require_relative './resources'
7
+
8
+ describe Krypt::ASN1::Null do
9
+ include Krypt::ASN1::Resources
10
+
11
+ let(:mod) { Krypt::ASN1 }
12
+ let(:klass) { mod::Null }
13
+ let(:decoder) { mod }
14
+ let(:asn1error) { mod::ASN1Error }
15
+
16
+ # For test against OpenSSL
17
+ #
18
+ #let(:mod) { OpenSSL::ASN1 }
19
+ #
20
+ # OpenSSL stub for signature mismatch
21
+ class OpenSSL::ASN1::Null
22
+ class << self
23
+ alias old_new new
24
+ def new(*args)
25
+ if args.size == 1
26
+ # nothing to do
27
+ elsif args.size > 0
28
+ args = [args[0], args[1], :IMPLICIT, args[2]]
29
+ else
30
+ args = [nil]
31
+ end
32
+ old_new(*args)
33
+ end
34
+ end
35
+ end
36
+
37
+ describe '#new' do
38
+ context 'constructs without value' do
39
+ subject { klass.new }
40
+
41
+ its(:tag) { should == Krypt::ASN1::NULL }
42
+ its(:tag_class) { should == :UNIVERSAL }
43
+ its(:value) { should == nil }
44
+ its(:infinite_length) { should == false }
45
+ end
46
+
47
+ context 'gets value for construct' do
48
+ subject { klass.new(nil) }
49
+
50
+ its(:tag) { should == Krypt::ASN1::NULL }
51
+ its(:tag_class) { should == :UNIVERSAL }
52
+ its(:value) { should == nil }
53
+ its(:infinite_length) { should == false }
54
+ end
55
+
56
+ it "only accepts nil as the value argument" do
57
+ -> { klass.new(1) }.should raise_error(ArgumentError)
58
+ end
59
+
60
+ context 'gets explicit tag number as the 2nd argument' do
61
+ subject { klass.new(nil, tag, :PRIVATE) }
62
+
63
+ context 'accepts default tag' do
64
+ let(:tag) { Krypt::ASN1::NULL }
65
+ its(:tag) { should == tag }
66
+ end
67
+
68
+ context 'accepts custom tag' do
69
+ let(:tag) { 14 }
70
+ its(:tag) { should == tag }
71
+ end
72
+ end
73
+
74
+ context 'gets tag class symbol as the 3rd argument' do
75
+ subject { klass.new(nil, Krypt::ASN1::NULL, tag_class) }
76
+
77
+ context 'accepts :UNIVERSAL' do
78
+ let(:tag_class) { :UNIVERSAL }
79
+ its(:tag_class) { should == tag_class }
80
+ end
81
+
82
+ context 'accepts :APPLICATION' do
83
+ let(:tag_class) { :APPLICATION }
84
+ its(:tag_class) { should == tag_class }
85
+ end
86
+
87
+ context 'accepts :CONTEXT_SPECIFIC' do
88
+ let(:tag_class) { :CONTEXT_SPECIFIC }
89
+ its(:tag_class) { should == tag_class }
90
+ end
91
+
92
+ context 'accepts :PRIVATE' do
93
+ let(:tag_class) { :PRIVATE }
94
+ its(:tag_class) { should == tag_class }
95
+ end
96
+
97
+ context 'accepts :IMPLICIT' do
98
+ let(:tag_class) { :IMPLICIT }
99
+ its(:tag_class) { should == tag_class }
100
+ end
101
+
102
+ context 'accepts :EXPLICIT' do
103
+ let(:tag_class) { :EXPLICIT }
104
+ its(:tag_class) { should == tag_class }
105
+ end
106
+ end
107
+
108
+ context 'when the 2nd argument is given but 3rd argument is omitted' do
109
+ subject { klass.new(nil, Krypt::ASN1::NULL) }
110
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
111
+ end
112
+ end
113
+
114
+ describe 'accessors' do
115
+ describe '#value' do
116
+ subject { o = klass.new(nil); o.value = value; o }
117
+
118
+ context 'accepts nil' do
119
+ let(:value) { nil }
120
+ its(:value) { should == nil }
121
+ end
122
+
123
+ it "only accepts nil as the value argument" do
124
+ asn1 = klass.new
125
+ asn1.value = 1
126
+ -> { asn1.to_der }.should raise_error asn1error
127
+ end
128
+ end
129
+
130
+ describe '#tag' do
131
+ subject { o = klass.new(nil); o.tag = tag; o }
132
+
133
+ context 'accepts default tag' do
134
+ let(:tag) { Krypt::ASN1::NULL }
135
+ its(:tag) { should == tag }
136
+ end
137
+
138
+ context 'accepts custom tag' do
139
+ let(:tag) { 14 }
140
+ its(:tag) { should == tag }
141
+ end
142
+ end
143
+
144
+ describe '#tag_class' do
145
+ subject { o = klass.new(nil); o.tag_class = tag_class; o }
146
+
147
+ context 'accepts :UNIVERSAL' do
148
+ let(:tag_class) { :UNIVERSAL }
149
+ its(:tag_class) { should == tag_class }
150
+ end
151
+
152
+ context 'accepts :APPLICATION' do
153
+ let(:tag_class) { :APPLICATION }
154
+ its(:tag_class) { should == tag_class }
155
+ end
156
+
157
+ context 'accepts :CONTEXT_SPECIFIC' do
158
+ let(:tag_class) { :CONTEXT_SPECIFIC }
159
+ its(:tag_class) { should == tag_class }
160
+ end
161
+
162
+ context 'accepts :PRIVATE' do
163
+ let(:tag_class) { :PRIVATE }
164
+ its(:tag_class) { should == tag_class }
165
+ end
166
+
167
+ context 'accepts :IMPLICIT' do
168
+ let(:tag_class) { :IMPLICIT }
169
+ its(:tag_class) { should == tag_class }
170
+ end
171
+
172
+ context 'accepts :EXPLICIT' do
173
+ let(:tag_class) { :EXPLICIT }
174
+ its(:tag_class) { should == tag_class }
175
+ end
176
+ end
177
+ end
178
+
179
+ describe '#to_der' do
180
+ context 'encodes a given value' do
181
+ subject { klass.new.to_der }
182
+ it { should == "\x05\x00" }
183
+ end
184
+
185
+ context 'encodes tag number' do
186
+ subject { klass.new(nil, tag, :PRIVATE).to_der }
187
+
188
+ context 'default tag' do
189
+ let(:tag) { Krypt::ASN1::NULL }
190
+ it { should == "\xC5\x00" }
191
+ end
192
+
193
+ context 'custom tag' do
194
+ let(:tag) { 14 }
195
+ it { should == "\xCE\x00" }
196
+ end
197
+
198
+ context 'nil' do
199
+ let(:tag) { nil }
200
+ it { -> { subject }.should raise_error asn1error }
201
+ end
202
+ end
203
+
204
+ context 'encodes tag class' do
205
+ subject { klass.new(nil, Krypt::ASN1::NULL, tag_class).to_der }
206
+
207
+ context 'UNIVERSAL' do
208
+ let(:tag_class) { :UNIVERSAL }
209
+ it { should == "\x05\x00" }
210
+ end
211
+
212
+ context 'APPLICATION' do
213
+ let(:tag_class) { :APPLICATION }
214
+ it { should == "\x45\x00" }
215
+ end
216
+
217
+ context 'CONTEXT_SPECIFIC' do
218
+ let(:tag_class) { :CONTEXT_SPECIFIC }
219
+ it { should == "\x85\x00" }
220
+ end
221
+
222
+ context 'PRIVATE' do
223
+ let(:tag_class) { :PRIVATE }
224
+ it { should == "\xC5\x00" }
225
+ end
226
+
227
+ context 'IMPLICIT' do
228
+ let(:tag_class) { :IMPLICIT }
229
+ it { should == "\x85\x00" }
230
+ end
231
+
232
+ context 'EXPLICIT' do
233
+ let(:tag_class) { :EXPLICIT }
234
+ it { should == "\xA5\x02\x05\x00" }
235
+ end
236
+
237
+ context nil do
238
+ let(:tag_class) { nil }
239
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check nil
240
+ end
241
+
242
+ context :no_such_class do
243
+ let(:tag_class) { :no_such_class }
244
+ it { -> { subject }.should raise_error asn1error }
245
+ end
246
+ end
247
+
248
+ context 'encodes values set via accessors' do
249
+ subject {
250
+ o = klass.new(nil)
251
+ o.value = value if defined? value
252
+ o.tag = tag if defined? tag
253
+ o.tag_class = tag_class if defined? tag_class
254
+ o.to_der
255
+ }
256
+
257
+ context 'value: 72' do
258
+ let(:value) { nil }
259
+ it { should == "\x05\x00" }
260
+ end
261
+
262
+ context 'custom tag' do
263
+ let(:value) { nil }
264
+ let(:tag) { 14 }
265
+ let(:tag_class) { :PRIVATE }
266
+ it { should == "\xCE\x00" }
267
+ end
268
+
269
+ context 'tag_class' do
270
+ let(:value) { nil }
271
+ let(:tag_class) { :APPLICATION }
272
+ it { should == "\x45\x00" }
273
+ end
274
+ end
275
+ end
276
+
277
+ describe '#encode_to' do
278
+ context 'encodes to an IO' do
279
+ subject { klass.new(value).encode_to(io); io }
280
+
281
+ context "StringIO" do
282
+ let(:value) { nil }
283
+ let(:io) { string_io_object }
284
+ its(:written_bytes) { should == "\x05\x00" }
285
+ end
286
+
287
+ context "Object responds to :write" do
288
+ let(:value) { nil }
289
+ let(:io) { writable_object }
290
+ its(:written_bytes) { should == "\x05\x00" }
291
+ end
292
+
293
+ context "raise IO error transparently" do
294
+ let(:value) { nil }
295
+ let(:io) { io_error_object }
296
+ it { -> { subject }.should raise_error asn1error }
297
+ end
298
+ end
299
+
300
+ it 'returns self' do
301
+ obj = klass.new(nil)
302
+ obj.encode_to(string_io_object).should == obj
303
+ end
304
+ end
305
+
306
+ describe 'extracted from ASN1.decode' do
307
+ subject { decoder.decode(der) }
308
+
309
+ context 'extracted value' do
310
+ let(:der) { "\x05\x00" }
311
+ its(:class) { should == klass }
312
+ its(:tag) { should == Krypt::ASN1::NULL }
313
+ its(:value) { should == nil }
314
+ end
315
+
316
+ context 'extracted tag class' do
317
+ context 'UNIVERSAL' do
318
+ let(:der) { "\x05\x00" }
319
+ its(:tag_class) { should == :UNIVERSAL }
320
+ end
321
+
322
+ context 'APPLICATION' do
323
+ let(:der) { "\x45\x00" }
324
+ its(:tag_class) { should == :APPLICATION }
325
+ end
326
+
327
+ context 'CONTEXT_SPECIFIC' do
328
+ let(:der) { "\x85\x00" }
329
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
330
+ end
331
+
332
+ context 'PRIVATE' do
333
+ let(:der) { "\xC5\x00" }
334
+ its(:tag_class) { should == :PRIVATE }
335
+ end
336
+
337
+ context "setting IMPLICIT will result in CONTEXT_SPECIFIC" do
338
+ let(:der) { "\x05\x00" }
339
+ it do
340
+ subject.tag_class = :IMPLICIT
341
+ subject.to_der.should == "\x85\x00"
342
+ end
343
+ end
344
+
345
+ context "setting EXPLICIT will reencode as CONTEXT_SPECIFIC" do
346
+ let(:der) { "\x05\x00" }
347
+ it do
348
+ subject.tag_class = :EXPLICIT
349
+ subject.tag = 0
350
+ subject.to_der.should == "\xA0\x02\x05\x00"
351
+ end
352
+ end
353
+ end
354
+
355
+ context 'rejects values with a length > 0' do
356
+ let(:der) { "\x05\x01\x00" }
357
+ it { -> { subject.value }.should raise_error asn1error }
358
+ end
359
+ end
360
+ end
@@ -0,0 +1,495 @@
1
+ # encoding: US-ASCII
2
+
3
+ require 'rspec'
4
+ require 'krypt'
5
+ require 'openssl'
6
+ require_relative './resources'
7
+
8
+ describe Krypt::ASN1::ObjectId do
9
+ include Krypt::ASN1::Resources
10
+
11
+ let(:mod) { Krypt::ASN1 }
12
+ let(:klass) { mod::ObjectId }
13
+ let(:decoder) { mod }
14
+ let(:asn1error) { mod::ASN1Error }
15
+
16
+ # For test against OpenSSL
17
+ #
18
+ #let(:mod) { OpenSSL::ASN1 }
19
+ #
20
+ # OpenSSL stub for signature mismatch
21
+ class OpenSSL::ASN1::ObjectId
22
+ class << self
23
+ alias old_new new
24
+ def new(*args)
25
+ if args.size > 1
26
+ args = [args[0], args[1], :IMPLICIT, args[2]]
27
+ end
28
+ old_new(*args)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe '#new' do
34
+ context 'gets value for construct' do
35
+ subject { klass.new(value) }
36
+
37
+ context 'accepts 1.0.8571.2' do
38
+ let(:value) { '1.0.8571.2' }
39
+ its(:tag) { should == Krypt::ASN1::OBJECT_ID }
40
+ its(:tag_class) { should == :UNIVERSAL }
41
+ its(:value) { should == '1.0.8571.2' }
42
+ its(:infinite_length) { should == false }
43
+ end
44
+ end
45
+
46
+ context 'gets explicit tag number as the 2nd argument' do
47
+ subject { klass.new('1.0.8571.2', tag, :PRIVATE) }
48
+
49
+ context 'accepts default tag' do
50
+ let(:tag) { Krypt::ASN1::OBJECT_ID }
51
+ its(:tag) { should == tag }
52
+ end
53
+
54
+ context 'accepts custom tag' do
55
+ let(:tag) { 14 }
56
+ its(:tag) { should == tag }
57
+ end
58
+ end
59
+
60
+ context 'gets tag class symbol as the 3rd argument' do
61
+ subject { klass.new('1.0.8571.2', Krypt::ASN1::OBJECT_ID, tag_class) }
62
+
63
+ context 'accepts :UNIVERSAL' do
64
+ let(:tag_class) { :UNIVERSAL }
65
+ its(:tag_class) { should == tag_class }
66
+ end
67
+
68
+ context 'accepts :APPLICATION' do
69
+ let(:tag_class) { :APPLICATION }
70
+ its(:tag_class) { should == tag_class }
71
+ end
72
+
73
+ context 'accepts :CONTEXT_SPECIFIC' do
74
+ let(:tag_class) { :CONTEXT_SPECIFIC }
75
+ its(:tag_class) { should == tag_class }
76
+ end
77
+
78
+ context 'accepts :PRIVATE' do
79
+ let(:tag_class) { :PRIVATE }
80
+ its(:tag_class) { should == tag_class }
81
+ end
82
+
83
+ context 'accepts :IMPLICIT' do
84
+ let(:tag_class) { :IMPLICIT }
85
+ its(:tag_class) { should == tag_class }
86
+ end
87
+
88
+ context 'accepts :EXPLICIT' do
89
+ let(:tag_class) { :EXPLICIT }
90
+ its(:tag_class) { should == tag_class }
91
+ end
92
+ end
93
+
94
+ context 'when the 2nd argument is given but 3rd argument is omitted' do
95
+ subject { klass.new('1.0.8571.2', Krypt::ASN1::OBJECT_ID) }
96
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
97
+ end
98
+ end
99
+
100
+ describe 'accessors' do
101
+ describe '#value' do
102
+ subject { o = klass.new(nil); o.value = value; o }
103
+
104
+ context 'accepts 1.0.8571.2' do
105
+ let(:value) { '1.0.8571.2' }
106
+ its(:tag) { should == Krypt::ASN1::OBJECT_ID }
107
+ its(:tag_class) { should == :UNIVERSAL }
108
+ its(:value) { should == '1.0.8571.2' }
109
+ its(:infinite_length) { should == false }
110
+ end
111
+ end
112
+
113
+ describe '#tag' do
114
+ subject { o = klass.new(nil); o.tag = tag; o }
115
+
116
+ context 'accepts default tag' do
117
+ let(:tag) { Krypt::ASN1::OBJECT_ID }
118
+ its(:tag) { should == tag }
119
+ end
120
+
121
+ context 'accepts custom tag' do
122
+ let(:tag) { 14 }
123
+ its(:tag) { should == tag }
124
+ end
125
+ end
126
+
127
+ describe '#tag_class' do
128
+ subject { o = klass.new(nil); o.tag_class = tag_class; o }
129
+
130
+ context 'accepts :UNIVERSAL' do
131
+ let(:tag_class) { :UNIVERSAL }
132
+ its(:tag_class) { should == tag_class }
133
+ end
134
+
135
+ context 'accepts :APPLICATION' do
136
+ let(:tag_class) { :APPLICATION }
137
+ its(:tag_class) { should == tag_class }
138
+ end
139
+
140
+ context 'accepts :CONTEXT_SPECIFIC' do
141
+ let(:tag_class) { :CONTEXT_SPECIFIC }
142
+ its(:tag_class) { should == tag_class }
143
+ end
144
+
145
+ context 'accepts :PRIVATE' do
146
+ let(:tag_class) { :PRIVATE }
147
+ its(:tag_class) { should == tag_class }
148
+ end
149
+
150
+ context 'accepts :IMPLICIT' do
151
+ let(:tag_class) { :IMPLICIT }
152
+ its(:tag_class) { should == tag_class }
153
+ end
154
+
155
+ context 'accepts :EXPLICIT' do
156
+ let(:tag_class) { :EXPLICIT }
157
+ its(:tag_class) { should == tag_class }
158
+ end
159
+ end
160
+ end
161
+
162
+ describe '#to_der' do
163
+ context 'encodes a given value' do
164
+ subject { klass.new(value).to_der }
165
+
166
+ context '1.0.8571.2' do
167
+ let(:value) { '1.0.8571.2' }
168
+ it { should == "\x06\x04\x28\xC2\x7B\x02" }
169
+ end
170
+
171
+ context '(empty)' do
172
+ let(:value) { '' }
173
+ it { -> { subject }.should raise_error asn1error }
174
+ end
175
+
176
+ context '1' do
177
+ let(:value) { '1' }
178
+ it { -> { subject }.should raise_error asn1error }
179
+ end
180
+
181
+ # oid[0] ::= 0, 1, 2
182
+ # oid[1] ::= 0, 1, 2, 3
183
+ # v[0] ::= oid[0] * 40 + oid[1]
184
+ context '2 octets optimization' do
185
+ context '0.0' do
186
+ let(:value) { '0.0' }
187
+ it { should == "\x06\x01\x00" }
188
+ end
189
+
190
+ context '0.3' do
191
+ let(:value) { '0.3' }
192
+ it { should == "\x06\x01\x03" }
193
+ end
194
+
195
+ context '1.0' do
196
+ let(:value) { '1.0' }
197
+ it { should == "\x06\x01\x28" }
198
+ end
199
+
200
+ context '1.3' do
201
+ let(:value) { '1.3' }
202
+ it { should == "\x06\x01\x2B" }
203
+ end
204
+ end
205
+
206
+ context '0.0.0.....0' do
207
+ let(:value) { (['0'] * 999).join('.') }
208
+ it { should == "\x06\x82\x03\xE6\x00" + "\x00" * 997 }
209
+ end
210
+
211
+ context '1.1.1.....1' do
212
+ let(:value) { (['1'] * 1000).join('.') }
213
+ it { should == "\x06\x82\x03\xE7\x29" + "\x01" * 998 }
214
+ end
215
+
216
+ context 'nil' do
217
+ let(:value) { nil }
218
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
219
+ end
220
+
221
+ context '(empty)' do
222
+ let(:value) { '' }
223
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
224
+ end
225
+
226
+ context 'single octet' do
227
+ let(:value) { '1' }
228
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
229
+ end
230
+
231
+ context 'non OID format' do
232
+ let(:value) { '1,0:1' }
233
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
234
+ end
235
+
236
+ context 'non number id' do
237
+ let(:value) { '1.0.ABC' }
238
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
239
+ end
240
+
241
+ context 'starts with .' do
242
+ let(:value) { '.0.8571.2' }
243
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
244
+ end
245
+
246
+ context 'illegal first octet (must be 0..2)' do
247
+ let(:value) { '3.0.8571.2' }
248
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
249
+ end
250
+
251
+ context 'illegal second octet (must be 0..39)' do
252
+ let(:value) { '1.40.8571.2' }
253
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check value
254
+ end
255
+
256
+ context 'rejects sub identifiers in the bignum range' do
257
+ let(:value) { "1.2." + "3" * 1000 + "4.5" }
258
+ it { -> { subject }.should raise_error asn1error }
259
+ end
260
+ end
261
+
262
+ context 'encodes tag number' do
263
+ subject { klass.new('1.0.8571.2', tag, :PRIVATE).to_der }
264
+
265
+ context 'default tag' do
266
+ let(:tag) { 6 }
267
+ it { should == "\xC6\x04\x28\xC2\x7B\x02" }
268
+ end
269
+
270
+ context 'custom tag' do
271
+ let(:tag) { 14 }
272
+ it { should == "\xCE\x04\x28\xC2\x7B\x02" }
273
+ end
274
+
275
+ context 'nil' do
276
+ let(:tag) { nil }
277
+ it { -> { subject }.should raise_error asn1error }
278
+ end
279
+ end
280
+
281
+ context 'encodes tag class' do
282
+ subject { klass.new('1.0.8571.2', Krypt::ASN1::OBJECT_ID, tag_class).to_der }
283
+
284
+ context 'UNIVERSAL' do
285
+ let(:tag_class) { :UNIVERSAL }
286
+ it { should == "\x06\x04\x28\xC2\x7B\x02" }
287
+ end
288
+
289
+ context 'APPLICATION' do
290
+ let(:tag_class) { :APPLICATION }
291
+ it { should == "\x46\x04\x28\xC2\x7B\x02" }
292
+ end
293
+
294
+ context 'CONTEXT_SPECIFIC' do
295
+ let(:tag_class) { :CONTEXT_SPECIFIC }
296
+ it { should == "\x86\x04\x28\xC2\x7B\x02" }
297
+ end
298
+
299
+ context 'PRIVATE' do
300
+ let(:tag_class) { :PRIVATE }
301
+ it { should == "\xC6\x04\x28\xC2\x7B\x02" }
302
+ end
303
+
304
+ context 'IMPLICIT' do
305
+ let(:tag_class) { :IMPLICIT }
306
+ it { should == "\x86\x04\x28\xC2\x7B\x02" }
307
+ end
308
+
309
+ context 'EXPLICIT' do
310
+ let(:tag_class) { :EXPLICIT }
311
+ it { should == "\xA6\x06\x06\x04\x28\xC2\x7B\x02" }
312
+ end
313
+
314
+ context nil do
315
+ let(:tag_class) { nil }
316
+ it { -> { subject }.should raise_error asn1error } # TODO: ossl does not check nil
317
+ end
318
+
319
+ context :no_such_class do
320
+ let(:tag_class) { :no_such_class }
321
+ it { -> { subject }.should raise_error asn1error }
322
+ end
323
+ end
324
+
325
+ context 'encodes values set via accessors' do
326
+ subject {
327
+ o = klass.new(nil)
328
+ o.value = value if defined? value
329
+ o.tag = tag if defined? tag
330
+ o.tag_class = tag_class if defined? tag_class
331
+ o.to_der
332
+ }
333
+
334
+ context 'value: 1.0.8571.2' do
335
+ let(:value) { '1.0.8571.2' }
336
+ it { should == "\x06\x04\x28\xC2\x7B\x02" }
337
+ end
338
+
339
+ context 'custom tag' do
340
+ let(:value) { '1.0.8571.2' }
341
+ let(:tag) { 14 }
342
+ let(:tag_class) { :PRIVATE }
343
+ it { should == "\xCE\x04\x28\xC2\x7B\x02" }
344
+ end
345
+
346
+ context 'tag_class' do
347
+ let(:value) { '1.0.8571.2' }
348
+ let(:tag_class) { :APPLICATION }
349
+ it { should == "\x46\x04\x28\xC2\x7B\x02" }
350
+ end
351
+ end
352
+ end
353
+
354
+ describe '#encode_to' do
355
+ context 'encodes to an IO' do
356
+ subject { klass.new(value).encode_to(io); io }
357
+
358
+ context "StringIO" do
359
+ let(:value) { '1.0.8571.2' }
360
+ let(:io) { string_io_object }
361
+ its(:written_bytes) { should == "\x06\x04\x28\xC2\x7B\x02" }
362
+ end
363
+
364
+ context "Object responds to :write" do
365
+ let(:value) { '1.0.8571.2' }
366
+ let(:io) { writable_object }
367
+ its(:written_bytes) { should == "\x06\x04\x28\xC2\x7B\x02" }
368
+ end
369
+
370
+ context "raise IO error transparently" do
371
+ let(:value) { '1.0.8571.2' }
372
+ let(:io) { io_error_object }
373
+ it { -> { subject }.should raise_error asn1error }
374
+ end
375
+ end
376
+
377
+ it 'returns self' do
378
+ obj = klass.new('1.0.8571.2')
379
+ obj.encode_to(string_io_object).should == obj
380
+ end
381
+ end
382
+
383
+ describe 'extracted from ASN1.decode' do
384
+ subject { decoder.decode(der) }
385
+
386
+ context 'extracted value' do
387
+ context '1.0.8571.2' do
388
+ let(:der) { "\x06\x04\x28\xC2\x7B\x02" }
389
+ its(:class) { should == klass }
390
+ its(:tag) { should == Krypt::ASN1::OBJECT_ID }
391
+ its(:value) { should == '1.0.8571.2' }
392
+ end
393
+
394
+ context '2 octets optimization' do
395
+ context '0.0' do
396
+ let(:der) { "\x06\x01\x00" }
397
+ its(:class) { should == klass }
398
+ its(:tag) { should == Krypt::ASN1::OBJECT_ID }
399
+ its(:value) { should == '0.0' } # "ITU-T" in OpenSSL
400
+ end
401
+
402
+ context '0.3' do
403
+ let(:der) { "\x06\x01\x03" }
404
+ its(:class) { should == klass }
405
+ its(:tag) { should == Krypt::ASN1::OBJECT_ID }
406
+ its(:value) { should == '0.3' }
407
+ end
408
+
409
+ context '1.0' do
410
+ let(:der) { "\x06\x01\x28" }
411
+ its(:class) { should == klass }
412
+ its(:tag) { should == Krypt::ASN1::OBJECT_ID }
413
+ its(:value) { should == '1.0' } # "ISO" in OpenSSL
414
+ end
415
+
416
+ context '1.3' do
417
+ let(:der) { "\x06\x01\x2B" }
418
+ its(:class) { should == klass }
419
+ its(:tag) { should == Krypt::ASN1::OBJECT_ID }
420
+ its(:value) { should == '1.3' } # "identified-organization" in OpenSSL
421
+ end
422
+ end
423
+
424
+ context '0.0.0.....0' do
425
+ let(:der) { "\x06\x82\x03\xE6\x00" + "\x00" * 997 }
426
+ its(:class) { should == klass }
427
+ its(:tag) { should == Krypt::ASN1::OBJECT_ID }
428
+ its(:value) { should == (['0'] * 999).join('.') }
429
+ end
430
+
431
+ context '1.1.1.....1' do
432
+ let(:der) { "\x06\x82\x03\xE7\x29" + "\x01" * 998 }
433
+ its(:class) { should == klass }
434
+ its(:tag) { should == Krypt::ASN1::OBJECT_ID }
435
+ its(:value) { should == (['1'] * 1000).join('.') }
436
+ end
437
+
438
+ context 'Illegal first octet too large (3.50.2.3)' do
439
+ let(:der) { "\x06\x03\xAA\x02\x03" }
440
+ it { -> { subject.value }.should raise_error asn1error }
441
+ end
442
+
443
+ context 'Illegal first sub id (4.2.0.0)' do
444
+ let(:der) { "\x06\x03\xA2\x00\x00" }
445
+ it { -> { subject.value }.should raise_error asn1error }
446
+ end
447
+
448
+ describe 'We cannot prevent this mistake, so the parsed value will be different than expected' do
449
+ context 'Illegal second sub id (1.40.0.0)' do
450
+ let(:der) { "\x06\x03\x50\x00\x00" }
451
+ its(:value) { should == "2.0.0.0" }
452
+ end
453
+ end
454
+ end
455
+
456
+ context 'extracted tag class' do
457
+ context 'UNIVERSAL' do
458
+ let(:der) { "\x06\x04\x28\xC2\x7B\x02" }
459
+ its(:tag_class) { should == :UNIVERSAL }
460
+ end
461
+
462
+ context 'APPLICATION' do
463
+ let(:der) { "\x46\x04\x28\xC2\x7B\x02" }
464
+ its(:tag_class) { should == :APPLICATION }
465
+ end
466
+
467
+ context 'CONTEXT_SPECIFIC' do
468
+ let(:der) { "\x86\x04\x28\xC2\x7B\x02" }
469
+ its(:tag_class) { should == :CONTEXT_SPECIFIC }
470
+ end
471
+
472
+ context 'PRIVATE' do
473
+ let(:der) { "\xC6\x04\x28\xC2\x7B\x02" }
474
+ its(:tag_class) { should == :PRIVATE }
475
+ end
476
+
477
+ context "setting IMPLICIT will result in CONTEXT_SPECIFIC" do
478
+ let(:der) { "\x06\x04\x28\xC2\x7B\x02" }
479
+ it do
480
+ subject.tag_class = :IMPLICIT
481
+ subject.to_der.should == "\x86\x04\x28\xC2\x7B\x02"
482
+ end
483
+ end
484
+
485
+ context "setting EXPLICIT will reencode as CONTEXT_SPECIFIC" do
486
+ let(:der) { "\x06\x04\x28\xC2\x7B\x02" }
487
+ it do
488
+ subject.tag_class = :EXPLICIT
489
+ subject.tag = 0
490
+ subject.to_der.should == "\xA0\x06\x06\x04\x28\xC2\x7B\x02"
491
+ end
492
+ end
493
+ end
494
+ end
495
+ end