rasn1 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 66f3cf5edaaabbd17a920296e943f8e46f5de81c
4
- data.tar.gz: a83fb189ba31da35c1dc1743a01675fb3ac270d1
3
+ metadata.gz: 379d5a61021e3b58ffb46317f72905e9e3972044
4
+ data.tar.gz: 60bb0d280cccd6c999744045fb45f334863d46f4
5
5
  SHA512:
6
- metadata.gz: fa8459ba40745b387cdde298ff577707c63fd41ee4a2646b639878fcbb695638050910b94ec638ce7f010b8053140e30aa305a0634f3508c6fb8e6c7a8a337c7
7
- data.tar.gz: a7bc698f83d23585dfd75b27cc46429c9f2ec84b6c36d77980fbb3d0423b8ead411cd9a700a4700b2164e117d247837d54771e66a5f8aaf03fa198b1336cb9b7
6
+ metadata.gz: beb7960cfdef060b22f81dea31d7b93ece7781afad2b0a7db92606b860e8ff00ab1ae7991a86d5594b97b18b53c2888d6d83f11e4fe6e84abb33cfdddb491d75
7
+ data.tar.gz: 2fe8288bb99e4c21ead959855e3b0611c182abc6f2e23a8a60ff0babe7ebe62ef9a7795ec8f0512d50792f2e02278b192e8d62879c6f7815836ebb3c2c3287a0
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Gem Version](https://badge.fury.io/rb/rasn1.svg)](https://badge.fury.io/rb/rasn1)
2
+
1
3
  # Rasn1
2
4
 
3
5
  Rasn1 will be a ruby ASN.1 library to encode, parse and decode ASN.1 data in DER format.
@@ -47,7 +49,7 @@ class ComplexRecord < RASN1::Model
47
49
  sequence :cplx_record,
48
50
  content: [boolean(:bool),
49
51
  octet_string(:data, explicit: 0),
50
- Record]
52
+ model(:a_record, Record)]
51
53
  end
52
54
  ```
53
55
 
data/lib/rasn1/model.rb CHANGED
@@ -40,41 +40,94 @@ module RASN1
40
40
  # class Record2 < RASN1::Model
41
41
  # sequence(:record2,
42
42
  # content: [boolean(:rented, default: false),
43
- # Record])
43
+ # model(:a_record, Record)])
44
44
  # end
45
45
  # Set values like this:
46
46
  # record2 = Record2.new
47
47
  # record2[:rented] = true
48
- # record2[:record][:id] = 65537
49
- # record2[:record][:room] = 43
48
+ # record2[:a_record][:id] = 65537
49
+ # record2[:a_record][:room] = 43
50
50
  # or like this:
51
- # record2 = Record2.new(rented: true, record: { id: 65537, room: 43 })
51
+ # record2 = Record2.new(rented: true, a_record: { id: 65537, room: 43 })
52
52
  # @author Sylvain Daubert
53
53
  class Model
54
54
 
55
55
  class << self
56
56
 
57
- # Define a SEQUENCE type. Should be used to define a new subclass of {Model}.
58
- # @param [Hash] options
59
- # @option options [Array] :content
60
- # @see Types::Sequence#initialize
61
- # @return [Types::Sequence]
62
- def sequence(name, options={})
63
- @records ||= {}
64
- @records[name] = Proc.new do
65
- seq = Types::Sequence.new(name, options)
66
- seq.value = options[:content] if options[:content]
67
- seq
68
- end
57
+ # Use another model in this model
58
+ # @param [String,Symbol] name
59
+ # @param [Class] model_klass
60
+ def model(name, model_klass)
61
+ @root = [name, model_klass]
62
+ end
63
+
64
+ # @method sequence(name, options)
65
+ # @see Types::Sequence#initialize
66
+ # @method set(name, options)
67
+ # @see Types::Set#initialize
68
+ # @method choice(name, options)
69
+ # @see Types::Choice#initialize
70
+ %w(sequence set choice).each do |type|
71
+ class_eval "def #{type}(name, options={})\n" \
72
+ " proc = Proc.new do\n" \
73
+ " Types::#{type.capitalize}.new(name, options)\n" \
74
+ " end\n" \
75
+ " @root = [name, proc]\n" \
76
+ " @root << options[:content] unless options[:content].nil?\n" \
77
+ " @root\n" \
78
+ "end"
69
79
  end
70
80
 
71
- # define all class methods to instance a ASN.1 TAG
81
+ # @method sequence_of(name, type, options)
82
+ # @see Types::SequenceOf#initialize
83
+ # @method set_of(name, type, options)
84
+ # @see Types::SetOf#initialize
85
+ %w(sequence set).each do |type|
86
+ klass_name = "Types::#{type.capitalize}Of"
87
+ class_eval "def #{type}_of(name, type, options={})\n" \
88
+ " proc = Proc.new do\n" \
89
+ " #{klass_name}.new(name, type, options)\n" \
90
+ " end\n" \
91
+ " @root = [name, proc]\n" \
92
+ "end"
93
+ end
94
+
95
+ # @method boolean(name, options)
96
+ # @see Types::Boolean#initialize
97
+ # @method integer(name, options)
98
+ # @see Types::Integer#initialize
99
+ # @method bit_string(name, options)
100
+ # @see Types::BitString#initialize
101
+ # @method octet_string(name, options)
102
+ # @see Types::OctetString#initialize
103
+ # @method null(name, options)
104
+ # @see Types::Null#initialize
105
+ # @method enumerated(name, options)
106
+ # @see Types::Enumerated#initialize
107
+ # @method utf8_string(name, options)
108
+ # @see Types::Utf8String#initialize
72
109
  Types.primitives.each do |prim|
110
+ next if prim == Types::ObjectId
73
111
  class_eval "def #{prim.type.downcase.gsub(/\s+/, '_')}(name, options={})\n" \
74
- " Proc.new { #{prim.to_s}.new(name, options) }\n" \
112
+ " proc = Proc.new { #{prim.to_s}.new(name, options) }\n" \
113
+ " @root = [name, proc]\n" \
75
114
  "end"
76
115
  end
77
116
 
117
+ # @note This method is named +objectid+ and not +object_id+ to not override
118
+ # +Object#object_id+.
119
+ # @see Types::ObjectId#initialize
120
+ def objectid(name, options={})
121
+ proc = Proc.new { Types::ObjectId.new(name, options) }
122
+ @root = [name, proc]
123
+ end
124
+
125
+ # @see Types::Any#initialize
126
+ def any(name, options={})
127
+ proc = Proc.new { Types::Any.new(name, options) }
128
+ @root = [name, proc]
129
+ end
130
+
78
131
  # Parse a DER/BER encoded string
79
132
  # @param [String] str
80
133
  # @param [Boolean] ber accept BER encoding or not
@@ -89,7 +142,8 @@ module RASN1
89
142
  # Create a new instance of a {Model}
90
143
  # @param [Hash] args
91
144
  def initialize(args={})
92
- set_elements
145
+ root = generate_root
146
+ set_elements *root
93
147
  initialize_elements self, args
94
148
  end
95
149
 
@@ -106,6 +160,12 @@ module RASN1
106
160
  @elements[@root].name
107
161
  end
108
162
 
163
+ # Get elements names
164
+ # @return [Array<Symbol,String>]
165
+ def keys
166
+ @elements.keys
167
+ end
168
+
109
169
  # Return a hash image of model
110
170
  # @return [Hash]
111
171
  def to_h
@@ -117,46 +177,56 @@ module RASN1
117
177
  @elements[@root].to_der
118
178
  end
119
179
 
180
+ # Get root element from model
181
+ # @return [Types::Base,Model]
182
+ def root
183
+ @elements[@root]
184
+ end
185
+
120
186
  # Parse a DER/BER encoded string, and modify object in-place.
121
187
  # @param [String] str
122
188
  # @param [Boolean] ber accept BER encoding or not
123
189
  # @return [Integer] number of parsed bytes
124
190
  def parse!(str, ber: false)
125
- @elements[@root].parse!(str, ber: ber)
191
+ @elements[@root].parse!(str.dup.force_encoding('BINARY'), ber: ber)
126
192
  end
127
193
 
128
194
  private
129
195
 
130
- def set_elements(element=nil)
131
- if element.nil?
132
- records = self.class.class_eval { @records }
133
- @root = records.keys.first
134
- @elements = {}
135
- @elements[@root] = records[@root].call
136
- if @elements[@root].value.is_a? Array
137
- @elements[@root].value = @elements[@root].value.map do |subel|
138
- se = case subel
139
- when Proc
140
- subel.call
141
- when Class
142
- subel.new
143
- end
144
- @elements[se.name] = se
145
- set_elements se if se.is_a? Types::Sequence
146
- se
196
+ def is_composed?(el)
197
+ [Types::Sequence, Types::Set].include? el.class
198
+ end
199
+
200
+ def is_of?(el)
201
+ [Types::SequenceOf, Types::SetOf].include? el.class
202
+ end
203
+
204
+ def get_type(proc_or_class, name=nil)
205
+ case proc_or_class
206
+ when Proc
207
+ proc_or_class.call
208
+ when Class
209
+ proc_or_class.new
210
+ end
211
+ end
212
+
213
+ def generate_root
214
+ root = self.class.class_eval { @root }
215
+ @root = root[0]
216
+ @elements = {}
217
+ @elements[@root] = get_type(root[1])
218
+ root
219
+ end
220
+
221
+ def set_elements(name, el, content=nil)
222
+ if content.is_a? Array
223
+ @elements[name].value = content.map do |name2, proc_or_class, content2|
224
+ subel = get_type(proc_or_class, name2)
225
+ @elements[name2] = subel
226
+ if is_composed?(subel) and content2.is_a? Array
227
+ set_elements(name2, proc_or_class, content2)
147
228
  end
148
- end
149
- else
150
- element.value.map! do |subel|
151
- se = case subel
152
- when Proc
153
- subel.call
154
- when Class
155
- subel.new
156
- end
157
- @elements[se.name] = se
158
- set_elements se if se.is_a? Types::Sequence
159
- se
229
+ subel
160
230
  end
161
231
  end
162
232
  end
@@ -168,7 +238,7 @@ module RASN1
168
238
  if obj[name].is_a? Model
169
239
  initialize_elements obj[name], value
170
240
  else
171
- raise ArgumentError, "element #{name}: may only pass a Hash for Sequence elements"
241
+ raise ArgumentError, "element #{name}: may only pass a Hash for Model elements"
172
242
  end
173
243
  else
174
244
  obj[name].value = value
@@ -178,20 +248,27 @@ module RASN1
178
248
  end
179
249
 
180
250
  def private_to_h(element)
181
- h = {}
182
- element.value.each do |subel|
183
- h[subel.name] = case subel
184
- when Types::Sequence
185
- private_to_h(subel)
186
- when Model
187
- subel.to_h[subel.name]
188
- else
189
- next if subel.value.nil? and subel.optional?
190
- subel.value
191
- end
251
+ if element.value.is_a? Array
252
+ h = {}
253
+ element.value.each do |subel|
254
+ case subel
255
+ when Types::Sequence, Types::Set
256
+ h[subel.name] = private_to_h(subel)
257
+ when Model
258
+ h[@elements.key(subel)] = subel.to_h[subel.name]
259
+ when Hash, Array
260
+ # Array of Hash for SequenceOf and SetOf
261
+ # Array of Array of... of Hash are nested SequenceOf or SetOf
262
+ return element.value
263
+ else
264
+ next if subel.value.nil? and subel.optional?
265
+ h[subel.name] = subel.value
266
+ end
267
+ end
268
+ h
269
+ else
270
+ element.value
192
271
  end
193
-
194
- h
195
272
  end
196
273
  end
197
274
  end
data/lib/rasn1/types.rb CHANGED
@@ -35,3 +35,4 @@ require_relative 'types/sequence_of'
35
35
  require_relative 'types/set'
36
36
  require_relative 'types/set_of'
37
37
  require_relative 'types/choice'
38
+ require_relative 'types/any'
@@ -0,0 +1,29 @@
1
+ module RASN1
2
+ module Types
3
+
4
+ # ASN.1 ANY: accpets any types
5
+ # @author Sylvain Daubert
6
+ class Any < Base
7
+
8
+ # @return [String] DER-formated string
9
+ def to_der
10
+ case @value
11
+ when Base, Model
12
+ @value.to_der
13
+ else
14
+ @value.to_s
15
+ end
16
+ end
17
+
18
+ # Parse a DER string. This method updates object: {#value} will a DER string.
19
+ # @param [String] der DER string
20
+ # @param [Boolean] ber if +true+, accept BER encoding
21
+ # @return [Integer] total number of parsed bytes
22
+ def parse!(der, ber: false)
23
+ total_length, = get_data(der, ber)
24
+ @value = der[0, total_length]
25
+ total_length
26
+ end
27
+ end
28
+ end
29
+ end
@@ -36,6 +36,9 @@ module RASN1
36
36
  # ctype = RASN1::Types::Integer.new(:ctype, explicit: 0) # with explicit, default #asn1_class is :context
37
37
  # atype = RASN1::Types::Integer.new(:atype, explicit: 1, class: :application)
38
38
  # ptype = RASN1::Types::Integer.new(:ptype, explicit: 2, class: :private)
39
+ # Sometimes, an EXPLICIT type should be CONSTRUCTED. To do that, use +:constructed+
40
+ # option:
41
+ # ptype = RASN1::Types::Integer.new(:ptype, explicit: 2, class: :private, constructed: true)
39
42
  #
40
43
  # Implicit tagged values may also be defined:
41
44
  # ctype_implicit = RASN1::Types::Integer.new(:ctype, implicit: 0)
@@ -56,7 +59,7 @@ module RASN1
56
59
  INDEFINITE_LENGTH = 0x80
57
60
 
58
61
  # @return [Symbol, String]
59
- attr_reader :name
62
+ attr_accessor :name
60
63
  # @return [Symbol]
61
64
  attr_reader :asn1_class
62
65
  # @return [Object,nil] default value, if defined
@@ -74,13 +77,19 @@ module RASN1
74
77
 
75
78
  # @param [Symbol, String] name name for this tag in grammar
76
79
  # @param [Hash] options
77
- # @option options [Symbol] :class ASN.1 tag class. Default value is +:universal+
80
+ # @option options [Symbol] :class ASN.1 tag class. Default value is +:universal+.
81
+ # If +:explicit+ or +:implicit:+ is defined, default value is +:context+.
78
82
  # @option options [::Boolean] :optional define this tag as optional. Default
79
83
  # is +false+
80
84
  # @option options [Object] :default default value for DEFAULT tag
81
85
  # @option options [Object] :value value to set
86
+ # @option options [::Integer] :implicit define an IMPLICIT tagged type
87
+ # @option options [::Integer] :explicit define an EXPLICIT tagged type
88
+ # @option options [::Boolean] :constructed if +true+, set type as constructed.
89
+ # May only be used when +:explicit+ is defined, else it is discarded.
82
90
  def initialize(name, options={})
83
91
  @name = name
92
+ @constructed = nil
84
93
 
85
94
  set_options options
86
95
  end
@@ -137,20 +146,12 @@ module RASN1
137
146
 
138
147
  # @return [::Boolean] +true+ if this is a primitive type
139
148
  def primitive?
140
- if self.class < Primitive
141
- true
142
- else
143
- false
144
- end
149
+ (self.class < Primitive) && !@constructed
145
150
  end
146
151
 
147
152
  # @return [::Boolean] +true+ if this is a constructed type
148
153
  def constructed?
149
- if self.class < Constructed
150
- true
151
- else
152
- false
153
- end
154
+ !!((self.class < Constructed) || @constructed)
154
155
  end
155
156
 
156
157
  # Get ASN.1 type
@@ -162,7 +163,12 @@ module RASN1
162
163
  # Get tag value
163
164
  # @return [Integer]
164
165
  def tag
165
- (@tag_value || self.class::TAG) | CLASSES[@asn1_class] | self.class::ASN1_PC
166
+ pc = if @constructed.nil?
167
+ self.class::ASN1_PC
168
+ else
169
+ Constructed::ASN1_PC
170
+ end
171
+ (@tag_value || self.class::TAG) | CLASSES[@asn1_class] | pc
166
172
  end
167
173
 
168
174
  # @abstract This method SHOULD be partly implemented by subclasses to parse
@@ -177,7 +183,8 @@ module RASN1
177
183
 
178
184
  total_length, data = get_data(der, ber)
179
185
  if explicit?
180
- type = self.class.new(@name)
186
+ # Delegate to #explicit type to generate sub-tag
187
+ type = explicit_type
181
188
  type.parse!(data)
182
189
  @value = type.value
183
190
  else
@@ -225,6 +232,7 @@ module RASN1
225
232
  if options[:explicit]
226
233
  @tag = :explicit
227
234
  @tag_value = options[:explicit]
235
+ @constructed = options[:constructed]
228
236
  elsif options[:implicit]
229
237
  @tag = :implicit
230
238
  @tag_value = options[:implicit]
@@ -241,7 +249,7 @@ module RASN1
241
249
  def build_tag
242
250
  if build_tag?
243
251
  if explicit?
244
- v = self.class.new(nil)
252
+ v = explicit_type
245
253
  v.value = @value
246
254
  encoded_value = v.to_der
247
255
  else
@@ -325,8 +333,12 @@ module RASN1
325
333
  [total_length, data]
326
334
  end
327
335
 
336
+ def explicit_type
337
+ self.class.new(@name)
338
+ end
339
+
328
340
  def raise_tag_error(expected_tag, tag)
329
- msg = "Expected tag #{tag2name(expected_tag)} but get #{tag2name(tag)}"
341
+ msg = "Expected #{tag2name(expected_tag)} but get #{tag2name(tag)}"
330
342
  msg << " for #@name"
331
343
  raise ASN1Error, msg
332
344
  end
@@ -18,6 +18,8 @@ module RASN1
18
18
  # A {EnumeratedError} is raised when set value is not in enumeration.
19
19
  # @author Sylvain Daubert
20
20
  class Enumerated < Integer
21
+ # @return [Hash]
22
+ attr_reader :enum
21
23
 
22
24
  # @param [Symbol, String] name name for this tag in grammar
23
25
  # @param [Hash] options
@@ -114,6 +116,10 @@ module RASN1
114
116
  @value = @enum.key(v)
115
117
  raise EnumeratedError, "TAG #@name: value #{v} not in enumeration" if @value.nil?
116
118
  end
119
+
120
+ def explicit_type
121
+ self.class.new(@name, enum: self.enum)
122
+ end
117
123
  end
118
124
  end
119
125
  end
@@ -18,6 +18,11 @@ module RASN1
18
18
  # RASN1::Types::Integer(:id, explicit: 0, optional: true),
19
19
  # RASN1::Types::Integer(:id, implicit: 1, default: 0)
20
20
  # ]
21
+ #
22
+ # A sequence may also be used without value to not parse sequence content:
23
+ # seq = RASN1::Types::Sequence.new(:seq)
24
+ # seq.parse!(der_string)
25
+ # seq.value # => String
21
26
  # @author Sylvain Daubert
22
27
  class Sequence < Constructed
23
28
  TAG = 0x10
@@ -25,14 +30,25 @@ module RASN1
25
30
  private
26
31
 
27
32
  def value_to_der
28
- @value.map { |element| element.to_der }.join
33
+ case @value
34
+ when Array
35
+ @value.map { |element| element.to_der }.join
36
+ else
37
+ @value.to_s
38
+ end
29
39
  end
30
40
 
31
41
  def der_to_value(der, ber:false)
32
- nb_bytes = 0
33
- @value.each do |element|
34
- nb_bytes += element.parse!(der[nb_bytes..-1])
35
- end
42
+ case @value
43
+ when Array
44
+ nb_bytes = 0
45
+ @value.each do |element|
46
+ nb_bytes += element.parse!(der[nb_bytes..-1])
47
+ end
48
+ else
49
+ @value = der
50
+ der.length
51
+ end
36
52
  end
37
53
  end
38
54
  end
@@ -5,6 +5,7 @@ module RASN1
5
5
  #
6
6
  # A SEQUENCE OF is an array of one ASN.1 type.
7
7
  #
8
+ # == Use with {Primitive} types
8
9
  # To encode this ASN.1 example:
9
10
  # Integers ::= SEQUENCE OF INTEGER
10
11
  # do:
@@ -13,6 +14,7 @@ module RASN1
13
14
  # # Set integer values
14
15
  # seqof.value = [1, 2, 3, 4]
15
16
  #
17
+ # == Use with {Constructed} types
16
18
  # SEQUENCE OF may be used to create sequence of composed types. For example:
17
19
  # composed_type = RASN1::Sequence.new(:comp)
18
20
  # commposed_type.value = [RASN1::Types::Integer(:id),
@@ -20,38 +22,54 @@ module RASN1
20
22
  # seqof = RASN1::SequenceOf.new(:comp, composed_type)
21
23
  # seqof.value << [0, 'data0']
22
24
  # seqof.value << [1, 'data1']
25
+ #
26
+ # == Use with {Model}
27
+ # SEQUENCE OF may also be used with a Model type:
28
+ # class MyModel < RASN1::Model
29
+ # sequence :seq,
30
+ # content: [boolean(:bool), integer(:int)]
31
+ # end
32
+ #
33
+ # seqof = RASN1::Types::SequenceOf.new(:record, MyModel)
34
+ # # set values
35
+ # seqof.value << { bool: true, int: 12 }
36
+ # seqof.value << { bool: false, int: 65535 }
37
+ # # Generate DER string
38
+ # der = seqof.to_der # => String
39
+ # # parse
40
+ # seqof.parse! der
23
41
  # @author Sylvain Daubert
24
42
  class SequenceOf < Constructed
25
43
  TAG = Sequence::TAG
26
44
 
27
45
  # @return [Class, Base]
28
- attr_reader :type
46
+ attr_reader :of_type
29
47
 
30
48
  # @param [Symbol, String] name name for this tag in grammar
31
- # @param [Class, Base] type base type for sequence of
49
+ # @param [Class, Base] of_type base type for sequence of
32
50
  # @see Base#initialize
33
- def initialize(name, type, options={})
51
+ def initialize(name, of_type, options={})
34
52
  super(name, options)
35
- @type = type
53
+ @of_type = of_type
36
54
  @value = []
37
55
  end
38
56
 
39
57
  private
40
58
 
41
- def type_class
42
- type.is_a?(Class) ? type : type.class
59
+ def of_type_class
60
+ @of_type.is_a?(Class) ? @of_type : @of_type.class
43
61
  end
44
62
 
45
- def composed_type?
46
- [Sequence, Set].include? type_class
63
+ def composed_of_type?
64
+ [Sequence, Set].include? of_type_class
47
65
  end
48
66
 
49
67
  def value_to_der
50
- if composed_type?
68
+ if composed_of_type?
51
69
  @value.map do |ary|
52
- s = type_class.new(@type.name)
70
+ s = of_type_class.new(@of_type.name)
53
71
  sval = []
54
- @type.value.each_with_index do |type, i|
72
+ @of_type.value.each_with_index do |type, i|
55
73
  type2 = type.dup
56
74
  type2.value = ary[i]
57
75
  sval << type2
@@ -59,8 +77,21 @@ module RASN1
59
77
  s.value = sval
60
78
  s.to_der
61
79
  end.join
80
+ elsif of_type_class < Model
81
+ if of_type_class.new.root.is_a? SequenceOf
82
+ @value.map do |ary|
83
+ model = of_type_class.new
84
+ model.root.value = ary
85
+ model.to_der
86
+ end.join
87
+ else
88
+ @value.map do |hsh|
89
+ model = of_type_class.new(hsh)
90
+ model.to_der
91
+ end.join
92
+ end
62
93
  else
63
- @value.map { |v| t = type_class.new(:t, value: v).to_der }.join
94
+ @value.map { |v| of_type_class.new(:t, value: v).to_der }.join
64
95
  end
65
96
  end
66
97
 
@@ -69,16 +100,28 @@ module RASN1
69
100
  nb_bytes = 0
70
101
 
71
102
  while nb_bytes < der.length
72
- of_type = composed_type? ? type.dup : type_class.new(:t)
73
- nb_bytes += of_type.parse!(der[nb_bytes, der.length])
74
- value = if composed_type?
75
- of_type.value.map { |obj| obj.value }
103
+ type = if composed_of_type?
104
+ @of_type.dup
105
+ elsif of_type_class < Model
106
+ of_type_class.new
107
+ else
108
+ of_type_class.new(:t)
109
+ end
110
+ nb_bytes += type.parse!(der[nb_bytes, der.length])
111
+ value = if composed_of_type?
112
+ type.value.map { |obj| obj.value }
113
+ elsif of_type_class < Model
114
+ type.to_h[type.to_h.keys.first]
76
115
  else
77
- of_type.value
116
+ type.value
78
117
  end
79
118
  @value << value
80
119
  end
81
120
  end
121
+
122
+ def explicit_type
123
+ self.class.new(@name, self.of_type)
124
+ end
82
125
  end
83
126
  end
84
127
  end
data/lib/rasn1/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RASN1
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/rasn1.gemspec CHANGED
@@ -20,6 +20,8 @@ Gem::Specification.new do |spec|
20
20
  #spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ['lib']
22
22
 
23
+ spec.required_ruby_version = '>= 2.1.0'
24
+
23
25
  spec.add_dependency 'yard', '~>0.9'
24
26
 
25
27
  spec.add_development_dependency 'bundler', '~> 1.13'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rasn1
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvain Daubert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-06 00:00:00.000000000 Z
11
+ date: 2017-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: yard
@@ -95,6 +95,7 @@ files:
95
95
  - lib/rasn1.rb
96
96
  - lib/rasn1/model.rb
97
97
  - lib/rasn1/types.rb
98
+ - lib/rasn1/types/any.rb
98
99
  - lib/rasn1/types/base.rb
99
100
  - lib/rasn1/types/bit_string.rb
100
101
  - lib/rasn1/types/boolean.rb
@@ -125,7 +126,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
125
126
  requirements:
126
127
  - - ">="
127
128
  - !ruby/object:Gem::Version
128
- version: '0'
129
+ version: 2.1.0
129
130
  required_rubygems_version: !ruby/object:Gem::Requirement
130
131
  requirements:
131
132
  - - ">="