rasn1 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +0 -1
- data/lib/rasn1/model.rb +107 -67
- data/lib/rasn1/types/any.rb +26 -15
- data/lib/rasn1/types/base.rb +100 -78
- data/lib/rasn1/types/bit_string.rb +30 -28
- data/lib/rasn1/types/boolean.rb +5 -0
- data/lib/rasn1/types/choice.rb +4 -4
- data/lib/rasn1/types/constructed.rb +0 -2
- data/lib/rasn1/types/enumerated.rb +6 -13
- data/lib/rasn1/types/generalized_time.rb +99 -56
- data/lib/rasn1/types/ia5string.rb +1 -1
- data/lib/rasn1/types/integer.rb +76 -55
- data/lib/rasn1/types/null.rb +3 -2
- data/lib/rasn1/types/object_id.rb +2 -2
- data/lib/rasn1/types/sequence.rb +22 -5
- data/lib/rasn1/types/sequence_of.rb +43 -31
- data/lib/rasn1/types/utc_time.rb +1 -1
- data/lib/rasn1/types/utf8_string.rb +1 -1
- data/lib/rasn1/types.rb +16 -15
- data/lib/rasn1/version.rb +1 -1
- data/lib/rasn1.rb +1 -1
- metadata +4 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0f5f3f69aaae20cfd16576f565bc52d198bea49921a0db15e3e2a95a4947853
|
4
|
+
data.tar.gz: c3c1f6b2d5019febcbff3812611d624094b7aaefc238bd70109d4c278be3af8c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51e54a40d6608074e76ba0d18d51462e82fba109a4258b9082875bafe36476060186d2081cabb4e2d17e1140f53a4700906a053fdb05638ceb060560a337d05b
|
7
|
+
data.tar.gz: 434ca0398606fb411351a2d43b6701b70f9512043abea8768e21832a2a1800be8347efef50b17b01239ce953b49cb21b64860e2d252cc64e9c696a514de564ea
|
data/README.md
CHANGED
data/lib/rasn1/model.rb
CHANGED
@@ -58,7 +58,10 @@ module RASN1
|
|
58
58
|
# All methods defined by root may be delegated by model, unless model also defines
|
59
59
|
# this method.
|
60
60
|
# @author Sylvain Daubert
|
61
|
-
class Model
|
61
|
+
class Model # rubocop:disable Metrics/ClassLength
|
62
|
+
# @private
|
63
|
+
Elem = Struct.new(:name, :proc_or_class, :content)
|
64
|
+
|
62
65
|
class << self
|
63
66
|
# @return [Hash]
|
64
67
|
attr_reader :options
|
@@ -66,8 +69,9 @@ module RASN1
|
|
66
69
|
# Use another model in this model
|
67
70
|
# @param [String,Symbol] name
|
68
71
|
# @param [Class] model_klass
|
72
|
+
# @return [Elem]
|
69
73
|
def model(name, model_klass)
|
70
|
-
@root =
|
74
|
+
@root = Elem.new(name, model_klass, nil)
|
71
75
|
end
|
72
76
|
|
73
77
|
# Update options of root element.
|
@@ -99,14 +103,17 @@ module RASN1
|
|
99
103
|
# @method sequence(name, options)
|
100
104
|
# @param [Symbol,String] name name of object in model
|
101
105
|
# @param [Hash] options
|
106
|
+
# @return [Elem]
|
102
107
|
# @see Types::Sequence#initialize
|
103
108
|
# @method set(name, options)
|
104
109
|
# @param [Symbol,String] name name of object in model
|
105
110
|
# @param [Hash] options
|
111
|
+
# @return [Elem]
|
106
112
|
# @see Types::Set#initialize
|
107
113
|
# @method choice(name, options)
|
108
114
|
# @param [Symbol,String] name name of object in model
|
109
115
|
# @param [Hash] options
|
116
|
+
# @return [Elem]
|
110
117
|
# @see Types::Choice#initialize
|
111
118
|
%w[sequence set choice].each do |type|
|
112
119
|
class_eval "def #{type}(name, options={})\n" \
|
@@ -114,9 +121,7 @@ module RASN1
|
|
114
121
|
" proc = proc do |opts|\n" \
|
115
122
|
" Types::#{type.capitalize}.new(options.merge(opts))\n" \
|
116
123
|
" end\n" \
|
117
|
-
" @root =
|
118
|
-
" @root << options[:content] unless options[:content].nil?\n" \
|
119
|
-
" @root\n" \
|
124
|
+
" @root = Elem.new(name, proc, options[:content])\n" \
|
120
125
|
'end'
|
121
126
|
end
|
122
127
|
|
@@ -124,11 +129,13 @@ module RASN1
|
|
124
129
|
# @param [Symbol,String] name name of object in model
|
125
130
|
# @param [Model, Types::Base] type type for SEQUENCE OF
|
126
131
|
# @param [Hash] options
|
132
|
+
# @return [Elem]
|
127
133
|
# @see Types::SequenceOf#initialize
|
128
134
|
# @method set_of(name, type, options)
|
129
135
|
# @param [Symbol,String] name name of object in model
|
130
136
|
# @param [Model, Types::Base] type type for SET OF
|
131
137
|
# @param [Hash] options
|
138
|
+
# @return [Elem]
|
132
139
|
# @see Types::SetOf#initialize
|
133
140
|
%w[sequence set].each do |type|
|
134
141
|
klass_name = "Types::#{type.capitalize}Of"
|
@@ -137,53 +144,64 @@ module RASN1
|
|
137
144
|
" proc = proc do |opts|\n" \
|
138
145
|
" #{klass_name}.new(type, options.merge(opts))\n" \
|
139
146
|
" end\n" \
|
140
|
-
" @root =
|
147
|
+
" @root = Elem.new(name, proc, nil)\n" \
|
141
148
|
'end'
|
142
149
|
end
|
143
150
|
|
144
151
|
# @method boolean(name, options)
|
145
152
|
# @param [Symbol,String] name name of object in model
|
146
153
|
# @param [Hash] options
|
154
|
+
# @return [Elem]
|
147
155
|
# @see Types::Boolean#initialize
|
148
156
|
# @method integer(name, options)
|
149
157
|
# @param [Symbol,String] name name of object in model
|
150
158
|
# @param [Hash] options
|
159
|
+
# @return [Elem]
|
151
160
|
# @see Types::Integer#initialize
|
152
161
|
# @method bit_string(name, options)
|
153
162
|
# @param [Symbol,String] name name of object in model
|
154
163
|
# @param [Hash] options
|
164
|
+
# @return [Elem]
|
155
165
|
# @see Types::BitString#initialize
|
156
166
|
# @method octet_string(name, options)
|
157
167
|
# @param [Symbol,String] name name of object in model
|
158
168
|
# @param [Hash] options
|
169
|
+
# @return [Elem]
|
159
170
|
# @see Types::OctetString#initialize
|
160
171
|
# @method null(name, options)
|
161
172
|
# @param [Symbol,String] name name of object in model
|
162
173
|
# @param [Hash] options
|
174
|
+
# @return [Elem]
|
163
175
|
# @see Types::Null#initialize
|
164
176
|
# @method enumerated(name, options)
|
165
177
|
# @param [Symbol,String] name name of object in model
|
166
178
|
# @param [Hash] options
|
179
|
+
# @return [Elem]
|
167
180
|
# @see Types::Enumerated#initialize
|
168
181
|
# @method utf8_string(name, options)
|
169
182
|
# @param [Symbol,String] name name of object in model
|
170
183
|
# @param [Hash] options
|
184
|
+
# @return [Elem]
|
171
185
|
# @see Types::Utf8String#initialize
|
172
186
|
# @method numeric_string(name, options)
|
173
187
|
# @param [Symbol,String] name name of object in model
|
174
188
|
# @param [Hash] options
|
189
|
+
# @return [Elem]
|
175
190
|
# @see Types::NumericString#initialize
|
176
191
|
# @method printable_string(name, options)
|
177
192
|
# @param [Symbol,String] name name of object in model
|
178
193
|
# @param [Hash] options
|
194
|
+
# @return [Elem]
|
179
195
|
# @see Types::PrintableString#initialize
|
180
196
|
# @method visible_string(name, options)
|
181
197
|
# @param [Symbol,String] name name of object in model
|
182
198
|
# @param [Hash] options
|
199
|
+
# @return [Elem]
|
183
200
|
# @see Types::VisibleString#initialize
|
184
201
|
# @method ia5_string(name, options)
|
185
202
|
# @param [Symbol,String] name name of object in model
|
186
203
|
# @param [Hash] options
|
204
|
+
# @return [Elem]
|
187
205
|
# @see Types::IA5String#initialize
|
188
206
|
Types.primitives.each do |prim|
|
189
207
|
next if prim == Types::ObjectId
|
@@ -194,28 +212,30 @@ module RASN1
|
|
194
212
|
" proc = proc do |opts|\n" \
|
195
213
|
" #{prim}.new(options.merge(opts))\n" \
|
196
214
|
" end\n" \
|
197
|
-
" @root =
|
215
|
+
" @root = Elem.new(name, proc, nil)\n" \
|
198
216
|
'end'
|
199
217
|
end
|
200
218
|
|
201
219
|
# @param [Symbol,String] name name of object in model
|
202
220
|
# @param [Hash] options
|
221
|
+
# @return [Elem]
|
203
222
|
# @note This method is named +objectid+ and not +object_id+ to not override
|
204
223
|
# +Object#object_id+.
|
205
224
|
# @see Types::ObjectId#initialize
|
206
225
|
def objectid(name, options={})
|
207
226
|
options[:name] = name
|
208
227
|
proc = proc { |opts| Types::ObjectId.new(options.merge(opts)) }
|
209
|
-
@root =
|
228
|
+
@root = Elem.new(name, proc, nil)
|
210
229
|
end
|
211
230
|
|
212
231
|
# @param [Symbol,String] name name of object in model
|
213
232
|
# @param [Hash] options
|
233
|
+
# @return [Elem]
|
214
234
|
# @see Types::Any#initialize
|
215
235
|
def any(name, options={})
|
216
236
|
options[:name] = name
|
217
237
|
proc = proc { |opts| Types::Any.new(options.merge(opts)) }
|
218
|
-
@root =
|
238
|
+
@root = Elem.new(name, proc, nil)
|
219
239
|
end
|
220
240
|
|
221
241
|
# Give type name (aka class name)
|
@@ -233,7 +253,7 @@ module RASN1
|
|
233
253
|
# @raise [ASN1Error] error on parsing
|
234
254
|
def parse(str, ber: false)
|
235
255
|
model = new
|
236
|
-
model.parse!
|
256
|
+
model.parse!(str, ber: ber)
|
237
257
|
model
|
238
258
|
end
|
239
259
|
end
|
@@ -242,8 +262,8 @@ module RASN1
|
|
242
262
|
# @param [Hash] args
|
243
263
|
def initialize(args={})
|
244
264
|
root = generate_root
|
245
|
-
set_elements(
|
246
|
-
initialize_elements
|
265
|
+
set_elements(root)
|
266
|
+
initialize_elements(self, args)
|
247
267
|
end
|
248
268
|
|
249
269
|
# Give access to element +name+ in model
|
@@ -263,10 +283,10 @@ module RASN1
|
|
263
283
|
@elements[name].value = value
|
264
284
|
end
|
265
285
|
|
266
|
-
# Get name
|
286
|
+
# Get name from root type
|
267
287
|
# @return [String,Symbol]
|
268
288
|
def name
|
269
|
-
@
|
289
|
+
@root_name
|
270
290
|
end
|
271
291
|
|
272
292
|
# Get elements names
|
@@ -281,15 +301,15 @@ module RASN1
|
|
281
301
|
private_to_h
|
282
302
|
end
|
283
303
|
|
284
|
-
# @return [String]
|
285
|
-
def to_der
|
286
|
-
@elements[@root].to_der
|
287
|
-
end
|
288
|
-
|
289
304
|
# Get root element from model
|
290
305
|
# @return [Types::Base,Model]
|
291
306
|
def root
|
292
|
-
@elements[@
|
307
|
+
@elements[@root_name]
|
308
|
+
end
|
309
|
+
|
310
|
+
# @return [String]
|
311
|
+
def to_der
|
312
|
+
root.to_der
|
293
313
|
end
|
294
314
|
|
295
315
|
# Give type name (aka class name)
|
@@ -304,25 +324,37 @@ module RASN1
|
|
304
324
|
# @return [Integer] number of parsed bytes
|
305
325
|
# @raise [ASN1Error] error on parsing
|
306
326
|
def parse!(str, ber: false)
|
307
|
-
|
327
|
+
root.parse!(str.dup.force_encoding('BINARY'), ber: ber)
|
308
328
|
end
|
309
329
|
|
310
330
|
# @overload value
|
311
331
|
# Get value of root element
|
312
332
|
# @return [Object,nil]
|
313
|
-
# @overload value(name)
|
333
|
+
# @overload value(name, *args)
|
314
334
|
# Direct access to the value of +name+ (nested) element of model.
|
315
335
|
# @param [String,Symbol] name
|
336
|
+
# @param [Array<Integer,String,Symbol>] args more argument to access element. May be
|
337
|
+
# used to access content of a SequenceOf or a SetOf
|
316
338
|
# @return [Object,nil]
|
317
339
|
# @return [Object,nil]
|
340
|
+
# @example
|
341
|
+
# class MyModel1 < RASN1::Model
|
342
|
+
# sequence('seq', content: [boolean('boolean'), integer('int')])
|
343
|
+
# end
|
344
|
+
# class MyModel2 < RASN1::Model
|
345
|
+
# sequence('root', content: [sequence_of('list', MyModel1)])
|
346
|
+
# end
|
347
|
+
# model = MyModel2.new
|
348
|
+
# model.parse!(der)
|
349
|
+
# # access to 2nd MyModel1.int in list
|
350
|
+
# model.value('list', 1, 'int')
|
318
351
|
def value(name=nil, *args)
|
319
352
|
if name.nil?
|
320
|
-
|
353
|
+
root.value
|
321
354
|
else
|
322
355
|
elt = by_name(name)
|
323
356
|
|
324
357
|
unless args.empty?
|
325
|
-
elt = elt.root if elt.is_a?(Model)
|
326
358
|
args.each do |arg|
|
327
359
|
elt = elt.root if elt.is_a?(Model)
|
328
360
|
elt = elt[arg]
|
@@ -336,8 +368,8 @@ module RASN1
|
|
336
368
|
# Delegate some methods to root element
|
337
369
|
# @param [Symbol] meth
|
338
370
|
def method_missing(meth, *args)
|
339
|
-
if
|
340
|
-
|
371
|
+
if root.respond_to? meth
|
372
|
+
root.send meth, *args
|
341
373
|
else
|
342
374
|
super
|
343
375
|
end
|
@@ -345,7 +377,7 @@ module RASN1
|
|
345
377
|
|
346
378
|
# @return [Boolean]
|
347
379
|
def respond_to_missing?(meth, *)
|
348
|
-
|
380
|
+
root.respond_to?(meth) || super
|
349
381
|
end
|
350
382
|
|
351
383
|
# @return [String]
|
@@ -385,6 +417,9 @@ module RASN1
|
|
385
417
|
[Types::Sequence, Types::Set].include? elt.class
|
386
418
|
end
|
387
419
|
|
420
|
+
# proc_or_class:
|
421
|
+
# * proc: a Types::Base subclass
|
422
|
+
# * class: a model
|
388
423
|
def get_type(proc_or_class, options={})
|
389
424
|
case proc_or_class
|
390
425
|
when Proc
|
@@ -395,20 +430,20 @@ module RASN1
|
|
395
430
|
end
|
396
431
|
|
397
432
|
def generate_root
|
398
|
-
|
399
|
-
@
|
433
|
+
class_element = self.class.class_eval { @root }
|
434
|
+
@root_name = class_element.name
|
400
435
|
@elements = {}
|
401
|
-
@elements[@
|
402
|
-
|
436
|
+
@elements[@root_name] = get_type(class_element.proc_or_class, self.class.options || {})
|
437
|
+
class_element
|
403
438
|
end
|
404
439
|
|
405
|
-
def set_elements(
|
406
|
-
return unless content.is_a? Array
|
440
|
+
def set_elements(element) # rubocop:disable Naming/AccessorMethodName
|
441
|
+
return unless element.content.is_a? Array
|
407
442
|
|
408
|
-
@elements[name].value = content.map do |
|
409
|
-
subel = get_type(proc_or_class)
|
410
|
-
@elements[
|
411
|
-
set_elements(
|
443
|
+
@elements[name].value = element.content.map do |another_element|
|
444
|
+
subel = get_type(another_element.proc_or_class)
|
445
|
+
@elements[another_element.name] = subel
|
446
|
+
set_elements(another_element) if composed?(subel) && another_element.content.is_a?(Array)
|
412
447
|
subel
|
413
448
|
end
|
414
449
|
end
|
@@ -423,54 +458,59 @@ module RASN1
|
|
423
458
|
|
424
459
|
initialize_elements obj[name], value
|
425
460
|
when Array
|
426
|
-
|
427
|
-
obj[name].root
|
428
|
-
else
|
429
|
-
obj[name]
|
430
|
-
end
|
431
|
-
if composed.of_type.is_a? Model
|
432
|
-
value.each do |el|
|
433
|
-
composed << initialize_elements(composed.of_type.class.new, el)
|
434
|
-
end
|
435
|
-
else
|
436
|
-
value.each do |el|
|
437
|
-
obj[name] << el
|
438
|
-
end
|
439
|
-
end
|
461
|
+
initialize_element_from_array(obj[name], value)
|
440
462
|
else
|
441
463
|
obj[name].value = value
|
442
464
|
end
|
443
465
|
end
|
444
466
|
end
|
445
467
|
|
468
|
+
def initialize_element_from_array(obj, value)
|
469
|
+
composed = obj.is_a?(Model) ? obj.root : obj
|
470
|
+
if composed.of_type.is_a?(Model)
|
471
|
+
value.each do |el|
|
472
|
+
composed << initialize_elements(composed.of_type.class.new, el)
|
473
|
+
end
|
474
|
+
else
|
475
|
+
value.each { |el| composed << el }
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
446
479
|
def private_to_h(element=nil)
|
447
|
-
my_element = element
|
448
|
-
my_element = root if my_element.nil?
|
480
|
+
my_element = element || root
|
449
481
|
my_element = my_element.root if my_element.is_a?(Model)
|
450
482
|
value = case my_element
|
451
483
|
when Types::SequenceOf
|
452
|
-
|
453
|
-
my_element.value.map { |el| el.to_h.values.first }
|
454
|
-
else
|
455
|
-
my_element.value.map { |el| private_to_h(el) }
|
456
|
-
end
|
484
|
+
sequence_of_to_h(my_element)
|
457
485
|
when Types::Sequence
|
458
|
-
|
459
|
-
next if el.optional? && el.value.nil?
|
460
|
-
|
461
|
-
name = el.is_a?(Model) ? @elements.key(el) : el.name
|
462
|
-
[name, private_to_h(el)]
|
463
|
-
end
|
464
|
-
seq.compact!
|
465
|
-
Hash[seq]
|
486
|
+
sequence_to_h(my_element)
|
466
487
|
else
|
467
488
|
my_element.value
|
468
489
|
end
|
469
490
|
if element.nil?
|
470
|
-
{ @
|
491
|
+
{ @root_name => value }
|
471
492
|
else
|
472
493
|
value
|
473
494
|
end
|
474
495
|
end
|
496
|
+
|
497
|
+
def sequence_of_to_h(elt)
|
498
|
+
if elt.of_type < Model
|
499
|
+
elt.value.map { |el| el.to_h.values.first }
|
500
|
+
else
|
501
|
+
elt.value.map { |el| private_to_h(el) }
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
def sequence_to_h(seq)
|
506
|
+
ary = seq.value.map do |el|
|
507
|
+
next if el.optional? && el.value.nil?
|
508
|
+
|
509
|
+
name = el.is_a?(Model) ? @elements.key(el) : el.name
|
510
|
+
[name, private_to_h(el)]
|
511
|
+
end
|
512
|
+
ary.compact!
|
513
|
+
ary.to_h
|
514
|
+
end
|
475
515
|
end
|
476
516
|
end
|
data/lib/rasn1/types/any.rb
CHANGED
@@ -9,13 +9,15 @@ module RASN1
|
|
9
9
|
class Any < Base
|
10
10
|
# @return [String] DER-formated string
|
11
11
|
def to_der
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
if value?
|
13
|
+
case @value
|
14
|
+
when Base, Model
|
15
|
+
@value.to_der
|
16
|
+
else
|
17
|
+
@value.to_s
|
18
|
+
end
|
17
19
|
else
|
18
|
-
|
20
|
+
optional? ? '' : Null.new.to_der
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
@@ -25,7 +27,7 @@ module RASN1
|
|
25
27
|
# @param [Boolean] ber if +true+, accept BER encoding
|
26
28
|
# @return [Integer] total number of parsed bytes
|
27
29
|
def parse!(der, ber: false)
|
28
|
-
if der.
|
30
|
+
if der.empty?
|
29
31
|
return 0 if optional?
|
30
32
|
|
31
33
|
raise ASN1Error, 'Expected ANY but get nothing'
|
@@ -35,25 +37,34 @@ module RASN1
|
|
35
37
|
total_length, = get_data(der[id_size..-1], ber)
|
36
38
|
total_length += id_size
|
37
39
|
|
40
|
+
@no_value = false
|
38
41
|
@value = der[0, total_length]
|
39
42
|
|
40
43
|
total_length
|
41
44
|
end
|
42
45
|
|
43
46
|
def inspect(level=0)
|
44
|
-
|
45
|
-
str
|
46
|
-
|
47
|
-
str << if @value.nil?
|
48
|
-
'(ANY) NULL'
|
47
|
+
str = common_inspect(level)
|
48
|
+
str << if !value?
|
49
|
+
'NULL'
|
49
50
|
elsif @value.is_a?(OctetString) || @value.is_a?(BitString)
|
50
|
-
"
|
51
|
+
"#{@value.type}: #{value.value.inspect}"
|
51
52
|
elsif @value.class < Base
|
52
|
-
"
|
53
|
+
"#{@value.type}: #{value.value}"
|
53
54
|
else
|
54
|
-
|
55
|
+
value.to_s.inspect
|
55
56
|
end
|
56
57
|
end
|
58
|
+
|
59
|
+
def common_inspect(level)
|
60
|
+
lvl = level >= 0 ? level : 0
|
61
|
+
str = ' ' * lvl
|
62
|
+
str << "#{@name} " unless @name.nil?
|
63
|
+
str << asn1_class.to_s.upcase << ' ' unless asn1_class == :universal
|
64
|
+
str << "[#{id}] EXPLICIT " if explicit?
|
65
|
+
str << "[#{id}] IMPLICIT " if implicit?
|
66
|
+
str << '(ANY) '
|
67
|
+
end
|
57
68
|
end
|
58
69
|
end
|
59
70
|
end
|