rasn1 0.8.0 → 0.9.0
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.
- 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
|