krypt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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