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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f4eb9957878c25e54a394fee02aab5a42aa1201ad6250f7f6a2a3992128c87d6
4
- data.tar.gz: 3b3d3c85d619ee7f78923d7f7c839874f329087b0b1a4094839b059daf94c2ec
3
+ metadata.gz: b0f5f3f69aaae20cfd16576f565bc52d198bea49921a0db15e3e2a95a4947853
4
+ data.tar.gz: c3c1f6b2d5019febcbff3812611d624094b7aaefc238bd70109d4c278be3af8c
5
5
  SHA512:
6
- metadata.gz: 9eb501aacf629355e56a4103dfc3e354bfa035c031a23f2dcc61f8add191a13960cd64ea68db36340694f3b20aba316c0088ebe91943d795405b11489be9342e
7
- data.tar.gz: 115cef9248e5251a24ec0bb6d6e977084cfb4ff78118a7f5be31ee8fea05a0c831b935fa72c18bdc08e71bb729a85cff2b394f4a84aafd56245f70908f0a4dc6
6
+ metadata.gz: 51e54a40d6608074e76ba0d18d51462e82fba109a4258b9082875bafe36476060186d2081cabb4e2d17e1140f53a4700906a053fdb05638ceb060560a337d05b
7
+ data.tar.gz: 434ca0398606fb411351a2d43b6701b70f9512043abea8768e21832a2a1800be8347efef50b17b01239ce953b49cb21b64860e2d252cc64e9c696a514de564ea
data/README.md CHANGED
@@ -1,5 +1,4 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/rasn1.svg)](https://badge.fury.io/rb/rasn1)
2
- [![Build Status](https://travis-ci.org/sdaubert/rasn1.svg?branch=master)](https://travis-ci.org/sdaubert/rasn1)
3
2
 
4
3
  # Rasn1
5
4
 
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 = [name, model_klass]
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 = [name, proc]\n" \
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 = [name, proc]\n" \
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 = [name, proc]\n" \
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 = [name, proc]
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 = [name, proc]
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! str, ber: ber
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(*root)
246
- initialize_elements self, args
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 frm root type
286
+ # Get name from root type
267
287
  # @return [String,Symbol]
268
288
  def name
269
- @root
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[@root]
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
- @elements[@root].parse!(str.dup.force_encoding('BINARY'), ber: ber)
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
- @elements[@root].value
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 @elements[@root].respond_to? meth
340
- @elements[@root].send meth, *args
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
- @elements[@root].respond_to?(meth) || super
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
- root = self.class.class_eval { @root }
399
- @root = root[0]
433
+ class_element = self.class.class_eval { @root }
434
+ @root_name = class_element.name
400
435
  @elements = {}
401
- @elements[@root] = get_type(root[1], self.class.options || {})
402
- root
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(name, _elt, content=nil)
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 |name2, proc_or_class, content2|
409
- subel = get_type(proc_or_class)
410
- @elements[name2] = subel
411
- set_elements(name2, proc_or_class, content2) if composed?(subel) && content2.is_a?(Array)
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
- composed = if obj[name].is_a? Model
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
- if my_element.of_type < Model
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
- seq = my_element.value.map do |el|
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
- { @root => value }
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
@@ -9,13 +9,15 @@ module RASN1
9
9
  class Any < Base
10
10
  # @return [String] DER-formated string
11
11
  def to_der
12
- case @value
13
- when Base, Model
14
- @value.to_der
15
- when nil
16
- optional? ? '' : Null.new.to_der
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
- @value.to_s
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.nil? || der.empty?
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
- lvl = level >= 0 ? level : 0
45
- str = ' ' * lvl
46
- str << "#{@name} " unless @name.nil?
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
- "(ANY) #{@value.type}: #{value.value.inspect}"
51
+ "#{@value.type}: #{value.value.inspect}"
51
52
  elsif @value.class < Base
52
- "(ANY) #{@value.type}: #{value.value}"
53
+ "#{@value.type}: #{value.value}"
53
54
  else
54
- "ANY: #{value.to_s.inspect}"
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