rasn1 0.11.0 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rasn1/errors.rb +13 -2
- data/lib/rasn1/model.rb +152 -47
- data/lib/rasn1/types/any.rb +4 -0
- data/lib/rasn1/types/base.rb +35 -26
- data/lib/rasn1/types/bit_string.rb +11 -8
- data/lib/rasn1/types/bmp_string.rb +30 -0
- data/lib/rasn1/types/choice.rb +1 -1
- data/lib/rasn1/types/constrained.rb +1 -1
- data/lib/rasn1/types/constructed.rb +17 -1
- data/lib/rasn1/types/generalized_time.rb +29 -42
- data/lib/rasn1/types/ia5string.rb +2 -2
- data/lib/rasn1/types/integer.rb +2 -1
- data/lib/rasn1/types/null.rb +4 -0
- data/lib/rasn1/types/numeric_string.rb +1 -1
- data/lib/rasn1/types/printable_string.rb +1 -1
- data/lib/rasn1/types/sequence_of.rb +1 -1
- data/lib/rasn1/types/utc_time.rb +3 -7
- data/lib/rasn1/types/utf8_string.rb +2 -2
- data/lib/rasn1/types.rb +24 -12
- data/lib/rasn1/version.rb +1 -1
- data/lib/rasn1/wrapper.rb +201 -0
- data/lib/rasn1.rb +5 -4
- metadata +8 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 552859c3f49caec5374c8db4459ad23e1f9c43e930b0d6511cab8f997c798d20
|
4
|
+
data.tar.gz: 29eaf2fc529b470c9bc6283efbaf82e580d5b4b86d5c46920ee4a882a18b0d72
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e5df0e417db7e1f02accae9cc4f17b4a49975d1dc17b716dbf587bb3f5e8ca68ed842d22358d7de037041255c164df5a92c6ada52adba944f0ac635793a64b1
|
7
|
+
data.tar.gz: e193284ea13ca5f80a460b8b390839a0283a8424ca8201f24cbd6113919399fcd5b83a2fc39dd5b26925187e19930a1aceccb1485255de8301435e20a2c82761
|
data/lib/rasn1/errors.rb
CHANGED
@@ -20,8 +20,14 @@ module RASN1
|
|
20
20
|
|
21
21
|
# CHOICE error: #chosen not set
|
22
22
|
class ChoiceError < RASN1::Error
|
23
|
+
# @param [Types::Base] object
|
24
|
+
def initialize(object)
|
25
|
+
@object = object
|
26
|
+
super()
|
27
|
+
end
|
28
|
+
|
23
29
|
def message
|
24
|
-
"CHOICE #{@name}: #chosen not set"
|
30
|
+
"CHOICE #{@object.name}: #chosen not set"
|
25
31
|
end
|
26
32
|
end
|
27
33
|
|
@@ -37,7 +43,12 @@ module RASN1
|
|
37
43
|
|
38
44
|
# @return [String]
|
39
45
|
def message
|
40
|
-
"Constraint not verified on #{object.inspect}"
|
46
|
+
"Constraint not verified on #{@object.inspect}"
|
41
47
|
end
|
42
48
|
end
|
49
|
+
|
50
|
+
# Exception raised when model validation fails
|
51
|
+
# @since 0.12.0
|
52
|
+
class ModelValidationError < Error
|
53
|
+
end
|
43
54
|
end
|
data/lib/rasn1/model.rb
CHANGED
@@ -57,16 +57,42 @@ module RASN1
|
|
57
57
|
#
|
58
58
|
# == Delegation
|
59
59
|
# {Model} may delegate some methods to its root element. Thus, if root element
|
60
|
-
# is, for example, a {
|
60
|
+
# is, for example, a {Types::Choice}, model may delegate +#chosen+ and +#chosen_value+.
|
61
61
|
#
|
62
62
|
# All methods defined by root may be delegated by model, unless model also defines
|
63
63
|
# this method.
|
64
64
|
# @author Sylvain Daubert
|
65
|
-
class
|
65
|
+
# @author adfoster-r7 ModelValidationError, track source location for dynamic class methods
|
66
|
+
class Model # rubocop:disable Metrics/ClassLength
|
66
67
|
# @private
|
67
|
-
Elem = Struct.new(:name, :proc_or_class, :content)
|
68
|
+
Elem = Struct.new(:name, :proc_or_class, :content) do
|
69
|
+
def initialize(name, proc_or_class, content)
|
70
|
+
if content.is_a?(Array)
|
71
|
+
duplicate_names = find_all_duplicate_names(content.map(&:name) + [name])
|
72
|
+
raise ModelValidationError, "Duplicate name #{duplicate_names.first} found" if duplicate_names.any?
|
73
|
+
end
|
74
|
+
|
75
|
+
super
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
# @param [Array<String>] names
|
81
|
+
# @return [Array<String>] The duplicate names found in the array
|
82
|
+
def find_all_duplicate_names(names)
|
83
|
+
names.group_by { |name| name }
|
84
|
+
.select { |_name, values| values.length > 1 }
|
85
|
+
.keys
|
86
|
+
end
|
87
|
+
end
|
68
88
|
|
69
89
|
# @private
|
90
|
+
WrapElem = Struct.new(:element, :options) do
|
91
|
+
def name
|
92
|
+
"#{element.name}_wrapper"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
70
96
|
module Accel
|
71
97
|
# @return [Hash]
|
72
98
|
attr_reader :options
|
@@ -79,6 +105,15 @@ module RASN1
|
|
79
105
|
@root = Elem.new(name, model_klass, nil)
|
80
106
|
end
|
81
107
|
|
108
|
+
# Use a {Wrapper} around a {Types::Base} or a {Model} object
|
109
|
+
# @param [Types::Base,Model] element
|
110
|
+
# @param [Hash] options
|
111
|
+
# @return [WrapElem]
|
112
|
+
# @since 0.12
|
113
|
+
def wrapper(element, options={})
|
114
|
+
@root = WrapElem.new(element, options)
|
115
|
+
end
|
116
|
+
|
82
117
|
# Update options of root element.
|
83
118
|
# May be used when subclassing.
|
84
119
|
# class Model1 < RASN1::Model
|
@@ -92,8 +127,13 @@ module RASN1
|
|
92
127
|
# end
|
93
128
|
# @param [Hash] options
|
94
129
|
# @return [void]
|
130
|
+
# @since 0.12.0 may change name through +:name+
|
95
131
|
def root_options(options)
|
96
132
|
@options = options
|
133
|
+
return unless options.key?(:name)
|
134
|
+
|
135
|
+
@root = @root.dup
|
136
|
+
@root.name = options[:name]
|
97
137
|
end
|
98
138
|
|
99
139
|
# On inheritance, create +@root+ class variable
|
@@ -105,33 +145,38 @@ module RASN1
|
|
105
145
|
klass.class_eval { @root = root }
|
106
146
|
end
|
107
147
|
|
148
|
+
# @since 0.11.0
|
149
|
+
# @since 0.12.0 track source location on error (adfoster-r7)
|
108
150
|
def define_type_accel_base(accel_name, klass)
|
109
|
-
singleton_class.class_eval
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
151
|
+
singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
152
|
+
def #{accel_name}(name, options={}) # def sequence(name, type, options)
|
153
|
+
options[:name] = name
|
154
|
+
proc = proc do |opts|
|
155
|
+
#{klass}.new(options.merge(opts)) # Sequence.new(options.merge(opts))
|
156
|
+
end
|
157
|
+
@root = Elem.new(name, proc, options[:content])
|
158
|
+
end
|
159
|
+
EVAL
|
118
160
|
end
|
119
161
|
|
162
|
+
# @since 0.11.0
|
163
|
+
# @since 0.12.0 track source location on error (adfoster-r7)
|
120
164
|
def define_type_accel_of(accel_name, klass)
|
121
|
-
singleton_class.class_eval
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
165
|
+
singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
166
|
+
def #{accel_name}_of(name, type, options={}) # def sequence_of(name, type, options)
|
167
|
+
options[:name] = name
|
168
|
+
proc = proc do |opts|
|
169
|
+
#{klass}.new(type, options.merge(opts)) # SequenceOf.new(type, options.merge(opts))
|
170
|
+
end
|
171
|
+
@root = Elem.new(name, proc, nil)
|
172
|
+
end
|
173
|
+
EVAL
|
130
174
|
end
|
131
175
|
|
132
176
|
# Define an accelarator to access a type in a model definition
|
133
177
|
# @param [String] accel_name
|
134
178
|
# @param [Class] klass
|
179
|
+
# @since 0.11.0
|
135
180
|
def define_type_accel(accel_name, klass)
|
136
181
|
if klass < Types::SequenceOf
|
137
182
|
define_type_accel_of(accel_name, klass)
|
@@ -184,17 +229,20 @@ module RASN1
|
|
184
229
|
|
185
230
|
extend Accel
|
186
231
|
|
187
|
-
#
|
232
|
+
# @!method sequence(name, options)
|
233
|
+
# @!scope class
|
188
234
|
# @param [Symbol,String] name name of object in model
|
189
235
|
# @param [Hash] options
|
190
236
|
# @return [Elem]
|
191
237
|
# @see Types::Sequence#initialize
|
192
|
-
#
|
238
|
+
# @!method set(name, options)
|
239
|
+
# @!scope class
|
193
240
|
# @param [Symbol,String] name name of object in model
|
194
241
|
# @param [Hash] options
|
195
242
|
# @return [Elem]
|
196
243
|
# @see Types::Set#initialize
|
197
|
-
#
|
244
|
+
# @!method choice(name, options)
|
245
|
+
# @!scope class
|
198
246
|
# @param [Symbol,String] name name of object in model
|
199
247
|
# @param [Hash] options
|
200
248
|
# @return [Elem]
|
@@ -203,13 +251,15 @@ module RASN1
|
|
203
251
|
self.define_type_accel_base(type, Types.const_get(type.capitalize))
|
204
252
|
end
|
205
253
|
|
206
|
-
#
|
254
|
+
# @!method sequence_of(name, type, options)
|
255
|
+
# @!scope class
|
207
256
|
# @param [Symbol,String] name name of object in model
|
208
257
|
# @param [Model, Types::Base] type type for SEQUENCE OF
|
209
258
|
# @param [Hash] options
|
210
259
|
# @return [Elem]
|
211
260
|
# @see Types::SequenceOf#initialize
|
212
|
-
#
|
261
|
+
# @!method set_of(name, type, options)
|
262
|
+
# @!scope class
|
213
263
|
# @param [Symbol,String] name name of object in model
|
214
264
|
# @param [Model, Types::Base] type type for SET OF
|
215
265
|
# @param [Hash] options
|
@@ -219,57 +269,68 @@ module RASN1
|
|
219
269
|
define_type_accel_of(type, Types.const_get("#{type.capitalize}Of"))
|
220
270
|
end
|
221
271
|
|
222
|
-
#
|
272
|
+
# @!method boolean(name, options)
|
273
|
+
# @!scope class
|
223
274
|
# @param [Symbol,String] name name of object in model
|
224
275
|
# @param [Hash] options
|
225
276
|
# @return [Elem]
|
226
277
|
# @see Types::Boolean#initialize
|
227
|
-
#
|
278
|
+
# @!method integer(name, options)
|
279
|
+
# @!scope class
|
228
280
|
# @param [Symbol,String] name name of object in model
|
229
281
|
# @param [Hash] options
|
230
282
|
# @return [Elem]
|
231
283
|
# @see Types::Integer#initialize
|
232
|
-
#
|
284
|
+
# @!method bit_string(name, options)
|
285
|
+
# @!scope class
|
233
286
|
# @param [Symbol,String] name name of object in model
|
234
287
|
# @param [Hash] options
|
235
288
|
# @return [Elem]
|
236
289
|
# @see Types::BitString#initialize
|
237
|
-
#
|
290
|
+
# @!method octet_string(name, options)
|
291
|
+
# @!scope class
|
238
292
|
# @param [Symbol,String] name name of object in model
|
239
293
|
# @param [Hash] options
|
240
294
|
# @return [Elem]
|
241
295
|
# @see Types::OctetString#initialize
|
242
|
-
#
|
296
|
+
# @!method null(name, options)
|
297
|
+
# @!scope class
|
243
298
|
# @param [Symbol,String] name name of object in model
|
244
299
|
# @param [Hash] options
|
245
300
|
# @return [Elem]
|
246
301
|
# @see Types::Null#initialize
|
247
|
-
#
|
302
|
+
# @!method enumerated(name, options)
|
303
|
+
# @!scope class
|
248
304
|
# @param [Symbol,String] name name of object in model
|
249
305
|
# @param [Hash] options
|
250
306
|
# @return [Elem]
|
251
307
|
# @see Types::Enumerated#initialize
|
252
|
-
#
|
308
|
+
# @!method utf8_string(name, options)
|
309
|
+
# @!scope class
|
253
310
|
# @param [Symbol,String] name name of object in model
|
254
311
|
# @param [Hash] options
|
255
312
|
# @return [Elem]
|
256
313
|
# @see Types::Utf8String#initialize
|
257
|
-
#
|
314
|
+
# @!method numeric_string(name, options)
|
315
|
+
# @!scope class
|
258
316
|
# @param [Symbol,String] name name of object in model
|
259
317
|
# @param [Hash] options
|
260
318
|
# @return [Elem]
|
261
319
|
# @see Types::NumericString#initialize
|
262
|
-
#
|
320
|
+
# @!method printable_string(name, options)
|
321
|
+
# @!scope class
|
263
322
|
# @param [Symbol,String] name name of object in model
|
264
323
|
# @param [Hash] options
|
265
324
|
# @return [Elem]
|
266
325
|
# @see Types::PrintableString#initialize
|
267
|
-
#
|
326
|
+
# @!method visible_string(name, options)
|
327
|
+
# @!scope class
|
268
328
|
# @param [Symbol,String] name name of object in model
|
269
329
|
# @param [Hash] options
|
270
330
|
# @return [Elem]
|
271
331
|
# @see Types::VisibleString#initialize
|
272
|
-
#
|
332
|
+
# @!method ia5_string(name, options)
|
333
|
+
# @!scope class
|
273
334
|
# @param [Symbol,String] name name of object in model
|
274
335
|
# @param [Hash] options
|
275
336
|
# @return [Elem]
|
@@ -285,7 +346,7 @@ module RASN1
|
|
285
346
|
# @param [Hash] args
|
286
347
|
def initialize(args={})
|
287
348
|
root = generate_root
|
288
|
-
|
349
|
+
generate_elements(root)
|
289
350
|
initialize_elements(self, args)
|
290
351
|
end
|
291
352
|
|
@@ -296,7 +357,7 @@ module RASN1
|
|
296
357
|
@elements[name]
|
297
358
|
end
|
298
359
|
|
299
|
-
# Set value of element +name+. Element should be a {Base}.
|
360
|
+
# Set value of element +name+. Element should be a {Types::Base}.
|
300
361
|
# @param [String,Symbol] name
|
301
362
|
# @param [Object] value
|
302
363
|
# @return [Object] value
|
@@ -460,14 +521,33 @@ module RASN1
|
|
460
521
|
class_element
|
461
522
|
end
|
462
523
|
|
463
|
-
def
|
524
|
+
def generate_elements(element)
|
525
|
+
if element.is_a?(WrapElem)
|
526
|
+
generate_wrapper(element)
|
527
|
+
return
|
528
|
+
end
|
464
529
|
return unless element.content.is_a? Array
|
465
530
|
|
466
531
|
@elements[name].value = element.content.map do |another_element|
|
467
|
-
|
468
|
-
|
469
|
-
|
532
|
+
add_subelement(another_element)
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
def generate_wrapper(wrap_elem)
|
537
|
+
inner_elem = wrap_elem.element
|
538
|
+
subel = add_subelement(inner_elem)
|
539
|
+
Wrapper.new(subel, wrap_elem.options)
|
540
|
+
end
|
541
|
+
|
542
|
+
def add_subelement(subelement)
|
543
|
+
case subelement
|
544
|
+
when Elem
|
545
|
+
subel = get_type(subelement.proc_or_class)
|
546
|
+
@elements[subelement.name] = subel
|
547
|
+
generate_elements(subelement) if composed?(subel) && subelement.content.is_a?(Array)
|
470
548
|
subel
|
549
|
+
when WrapElem
|
550
|
+
generate_wrapper(subelement)
|
471
551
|
end
|
472
552
|
end
|
473
553
|
|
@@ -477,7 +557,7 @@ module RASN1
|
|
477
557
|
|
478
558
|
case value
|
479
559
|
when Hash
|
480
|
-
raise ArgumentError, "element #{name}: may only pass a Hash for Model elements" unless obj[name].is_a?
|
560
|
+
raise ArgumentError, "element #{name}: may only pass a Hash for Model elements" unless obj[name].is_a?(Model)
|
481
561
|
|
482
562
|
initialize_elements obj[name], value
|
483
563
|
when Array
|
@@ -499,7 +579,7 @@ module RASN1
|
|
499
579
|
end
|
500
580
|
end
|
501
581
|
|
502
|
-
def private_to_h(element=nil)
|
582
|
+
def private_to_h(element=nil) # rubocop:disable Metrics/CyclomaticComplexity
|
503
583
|
my_element = element || root
|
504
584
|
my_element = my_element.root if my_element.is_a?(Model)
|
505
585
|
value = case my_element
|
@@ -507,6 +587,13 @@ module RASN1
|
|
507
587
|
sequence_of_to_h(my_element)
|
508
588
|
when Types::Sequence
|
509
589
|
sequence_to_h(my_element)
|
590
|
+
# @author adfoster-r7
|
591
|
+
when Types::Choice
|
592
|
+
raise ChoiceError.new(my_element) if my_element.chosen.nil?
|
593
|
+
|
594
|
+
private_to_h(my_element.value[my_element.chosen])
|
595
|
+
when Wrapper
|
596
|
+
wrapper_to_h(my_element)
|
510
597
|
else
|
511
598
|
my_element.value
|
512
599
|
end
|
@@ -529,11 +616,29 @@ module RASN1
|
|
529
616
|
ary = seq.value.map do |el|
|
530
617
|
next if el.optional? && el.value.nil?
|
531
618
|
|
532
|
-
|
533
|
-
|
619
|
+
case el
|
620
|
+
when Model
|
621
|
+
hsh = el.to_h
|
622
|
+
hsh = hsh[hsh.keys.first]
|
623
|
+
[@elements.key(el), hsh]
|
624
|
+
when Wrapper
|
625
|
+
[@elements.key(el.element), wrapper_to_h(el)]
|
626
|
+
else
|
627
|
+
[el.name, private_to_h(el)]
|
628
|
+
end
|
534
629
|
end
|
535
630
|
ary.compact!
|
536
631
|
ary.to_h
|
537
632
|
end
|
633
|
+
|
634
|
+
def wrapper_to_h(wrap)
|
635
|
+
case wrap.element
|
636
|
+
when Model
|
637
|
+
hsh = wrap.element.to_h
|
638
|
+
hsh[hsh.keys.first]
|
639
|
+
else
|
640
|
+
private_to_h(wrap.element)
|
641
|
+
end
|
642
|
+
end
|
538
643
|
end
|
539
644
|
end
|
data/lib/rasn1/types/any.rb
CHANGED
data/lib/rasn1/types/base.rb
CHANGED
@@ -69,6 +69,8 @@ module RASN1
|
|
69
69
|
attr_reader :asn1_class
|
70
70
|
# @return [Object,nil] default value, if defined
|
71
71
|
attr_reader :default
|
72
|
+
# @return [Hash[Symbol, Object]]
|
73
|
+
attr_reader :options
|
72
74
|
|
73
75
|
# Get ASN.1 type
|
74
76
|
# @return [String]
|
@@ -116,7 +118,8 @@ module RASN1
|
|
116
118
|
# @option options [::String] :name name for this node
|
117
119
|
def initialize(options={})
|
118
120
|
@constructed = nil
|
119
|
-
|
121
|
+
set_value(options.delete(:value))
|
122
|
+
self.options = options
|
120
123
|
specific_initializer
|
121
124
|
end
|
122
125
|
|
@@ -253,11 +256,38 @@ module RASN1
|
|
253
256
|
(other.class == self.class) && (other.to_der == self.to_der)
|
254
257
|
end
|
255
258
|
|
259
|
+
# Set options to this object
|
260
|
+
# @param [Hash] options
|
261
|
+
# @return [void]
|
262
|
+
# @since 0.12
|
263
|
+
def options=(options)
|
264
|
+
set_class options[:class]
|
265
|
+
set_optional options[:optional]
|
266
|
+
set_default options[:default]
|
267
|
+
set_tag options
|
268
|
+
@name = options[:name]
|
269
|
+
@options = options
|
270
|
+
end
|
271
|
+
|
272
|
+
# Say if a value is set
|
273
|
+
# @return [Boolean]
|
274
|
+
# @since 0.12.0
|
275
|
+
def value?
|
276
|
+
!@no_value
|
277
|
+
end
|
278
|
+
|
279
|
+
# Say if DER can be built (not default value, not optional without value, has a value)
|
280
|
+
# @return [Boolean]
|
281
|
+
# @since 0.12.0
|
282
|
+
def can_build?
|
283
|
+
value? && (@default.nil? || (@value != @default))
|
284
|
+
end
|
285
|
+
|
256
286
|
private
|
257
287
|
|
258
288
|
def pc_bit
|
259
289
|
if @constructed.nil?
|
260
|
-
self.class
|
290
|
+
self.class.const_get(:ASN1_PC)
|
261
291
|
elsif @constructed # true
|
262
292
|
Constructed::ASN1_PC
|
263
293
|
else # false
|
@@ -296,16 +326,6 @@ module RASN1
|
|
296
326
|
@value = der
|
297
327
|
end
|
298
328
|
|
299
|
-
def set_options(options) # rubocop:disable Naming/AccessorMethodName
|
300
|
-
set_class options[:class]
|
301
|
-
set_optional options[:optional]
|
302
|
-
set_default options[:default]
|
303
|
-
set_tag options
|
304
|
-
set_value options[:value]
|
305
|
-
@name = options[:name]
|
306
|
-
@options = options
|
307
|
-
end
|
308
|
-
|
309
329
|
def set_class(asn1_class) # rubocop:disable Naming/AccessorMethodName
|
310
330
|
case asn1_class
|
311
331
|
when nil
|
@@ -330,17 +350,15 @@ module RASN1
|
|
330
350
|
# handle undocumented option +:tag_value+, used internally by
|
331
351
|
# {RASN1.parse} to parse non-universal class tags.
|
332
352
|
def set_tag(options) # rubocop:disable Naming/AccessorMethodName
|
353
|
+
@constructed = options[:constructed]
|
333
354
|
if options[:explicit]
|
334
355
|
@tag = :explicit
|
335
356
|
@id_value = options[:explicit]
|
336
|
-
@constructed = options[:constructed]
|
337
357
|
elsif options[:implicit]
|
338
358
|
@tag = :implicit
|
339
359
|
@id_value = options[:implicit]
|
340
|
-
@constructed = options[:constructed]
|
341
360
|
elsif options[:tag_value]
|
342
361
|
@id_value = options[:tag_value]
|
343
|
-
@constructed = options[:constructed]
|
344
362
|
end
|
345
363
|
|
346
364
|
@asn1_class = :context if defined?(@tag) && (@asn1_class == :universal)
|
@@ -357,15 +375,6 @@ module RASN1
|
|
357
375
|
value
|
358
376
|
end
|
359
377
|
|
360
|
-
def value?
|
361
|
-
!@no_value
|
362
|
-
end
|
363
|
-
|
364
|
-
def can_build?
|
365
|
-
(@default.nil? || (value? && (@value != @default))) &&
|
366
|
-
(!optional? || value?)
|
367
|
-
end
|
368
|
-
|
369
378
|
def build
|
370
379
|
if can_build?
|
371
380
|
if explicit?
|
@@ -382,9 +391,9 @@ module RASN1
|
|
382
391
|
end
|
383
392
|
|
384
393
|
def id_value
|
385
|
-
return @id_value if defined?
|
394
|
+
return @id_value if defined?(@id_value) && !@id_value.nil?
|
386
395
|
|
387
|
-
self.class
|
396
|
+
self.class.const_get(:ID)
|
388
397
|
end
|
389
398
|
|
390
399
|
def encode_identifier_octets
|
@@ -42,14 +42,14 @@ module RASN1
|
|
42
42
|
str << " #{value.inspect} (bit length: #{bit_length})"
|
43
43
|
end
|
44
44
|
|
45
|
-
private
|
46
|
-
|
47
45
|
def can_build?
|
48
|
-
|
49
|
-
(@bit_length == @default_bit_length))) &&
|
50
|
-
!(optional? && !value?)
|
46
|
+
super || (!@default.nil? && (@bit_length != @default_bit_length))
|
51
47
|
end
|
52
48
|
|
49
|
+
private
|
50
|
+
|
51
|
+
# @author Sylvain Daubert
|
52
|
+
# @author adfoster-r7
|
53
53
|
def value_to_der
|
54
54
|
raise ASN1Error, "#{@name}: bit length is not set" if bit_length.nil?
|
55
55
|
|
@@ -70,9 +70,8 @@ module RASN1
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def generate_value_with_correct_length
|
73
|
-
value = @value || ''
|
74
|
-
value << "\x00" while value.length * 8 < @bit_length.to_i
|
75
|
-
value.force_encoding('BINARY')
|
73
|
+
value = (@value || '').dup.force_encoding('BINARY')
|
74
|
+
value << "\x00".b while value.length * 8 < @bit_length.to_i
|
76
75
|
return value unless value.length * 8 > @bit_length.to_i
|
77
76
|
|
78
77
|
max_len = @bit_length.to_i / 8 + ((@bit_length.to_i % 8).positive? ? 1 : 0)
|
@@ -85,6 +84,10 @@ module RASN1
|
|
85
84
|
@bit_length = value.length * 8 - unused
|
86
85
|
@value = value
|
87
86
|
end
|
87
|
+
|
88
|
+
def explicit_type
|
89
|
+
self.class.new(value: @value, bit_length: @bit_length)
|
90
|
+
end
|
88
91
|
end
|
89
92
|
end
|
90
93
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RASN1
|
4
|
+
module Types
|
5
|
+
# ASN.1 BmpString
|
6
|
+
# @since 0.12.0
|
7
|
+
# @author adfoster-r7
|
8
|
+
class BmpString < OctetString
|
9
|
+
# BmpString id value
|
10
|
+
ID = 30
|
11
|
+
|
12
|
+
# Get ASN.1 type
|
13
|
+
# @return [String]
|
14
|
+
def self.type
|
15
|
+
'BmpString'
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def value_to_der
|
21
|
+
@value.to_s.dup.encode('UTF-16BE').b
|
22
|
+
end
|
23
|
+
|
24
|
+
def der_to_value(der, ber: false)
|
25
|
+
super
|
26
|
+
@value = der.to_s.dup.force_encoding('UTF-16BE')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/rasn1/types/choice.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module RASN1
|
4
4
|
module Types
|
5
5
|
# Mixin to had constraints on a RASN1 type.
|
6
|
-
# Should not be used directly but through {
|
6
|
+
# Should not be used directly but through {Types.define_type}.
|
7
7
|
# @version 0.11.0
|
8
8
|
# @author Sylvain Daubert
|
9
9
|
module Constrained
|
@@ -10,6 +10,22 @@ module RASN1
|
|
10
10
|
# Constructed value
|
11
11
|
ASN1_PC = 0x20
|
12
12
|
|
13
|
+
# @return [Boolean]
|
14
|
+
# @since 0.12.0
|
15
|
+
# @see Base#can_build?
|
16
|
+
def can_build? # rubocop:disable Metrics/CyclomaticComplexity
|
17
|
+
return super unless @value.is_a?(Array) && optional?
|
18
|
+
return false unless super
|
19
|
+
|
20
|
+
@value.any? do |el|
|
21
|
+
el.can_build? && (
|
22
|
+
el.primitive? ||
|
23
|
+
(el.value.respond_to?(:empty?) ? !el.value.empty? : !el.value.nil?))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param [::Integer] level (default: 0)
|
28
|
+
# @return [String]
|
13
29
|
def inspect(level=0)
|
14
30
|
case @value
|
15
31
|
when Array
|
@@ -18,7 +34,7 @@ module RASN1
|
|
18
34
|
level = level.abs + 1
|
19
35
|
@value.each do |item|
|
20
36
|
case item
|
21
|
-
when Base, Model
|
37
|
+
when Base, Model, Wrapper
|
22
38
|
str << "#{item.inspect(level)}\n"
|
23
39
|
else
|
24
40
|
str << ' ' * level
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'strptime'
|
4
|
+
|
3
5
|
module RASN1
|
4
6
|
module Types
|
5
7
|
# ASN.1 GeneralizedTime
|
@@ -24,25 +26,33 @@ module RASN1
|
|
24
26
|
# GeneralizedTime id value
|
25
27
|
ID = 24
|
26
28
|
|
29
|
+
# @private
|
30
|
+
HOUR_TO_SEC = 3600
|
31
|
+
# @private
|
32
|
+
MINUTE_TO_SEC = 60
|
33
|
+
# @private
|
34
|
+
SECOND_TO_SEC = 1
|
35
|
+
|
27
36
|
# Get ASN.1 type
|
28
37
|
# @return [String]
|
29
38
|
def self.type
|
30
39
|
'GeneralizedTime'
|
31
40
|
end
|
32
41
|
|
33
|
-
# @return [
|
42
|
+
# @return [Time]
|
34
43
|
def void_value
|
35
|
-
|
44
|
+
Time.now
|
36
45
|
end
|
37
46
|
|
38
47
|
private
|
39
48
|
|
40
49
|
def value_to_der
|
41
|
-
|
42
|
-
|
50
|
+
utc_value = @value.getutc
|
51
|
+
if utc_value.nsec.positive?
|
52
|
+
der = utc_value.strftime('%Y%m%d%H%M%S.%9NZ')
|
43
53
|
der.sub(/0+Z/, 'Z')
|
44
54
|
else
|
45
|
-
|
55
|
+
utc_value.strftime('%Y%m%d%H%M%SZ')
|
46
56
|
end
|
47
57
|
end
|
48
58
|
|
@@ -61,18 +71,13 @@ module RASN1
|
|
61
71
|
end
|
62
72
|
|
63
73
|
def value_when_fraction_empty(date_hour)
|
64
|
-
utc_offset_forced = false
|
65
|
-
|
66
74
|
if (date_hour[-1] != 'Z') && (date_hour !~ /[+-]\d+$/)
|
67
75
|
# If not UTC, have to add offset with UTC to force
|
68
|
-
#
|
69
|
-
# may be errored because of DST.
|
76
|
+
# Strptime to generate a local time.
|
70
77
|
date_hour << Time.now.strftime('%z')
|
71
|
-
utc_offset_forced = true
|
72
78
|
end
|
73
79
|
|
74
80
|
value_from(date_hour)
|
75
|
-
fix_dst if utc_offset_forced
|
76
81
|
end
|
77
82
|
|
78
83
|
def value_when_fraction_ends_with_z(date_hour, fraction)
|
@@ -90,62 +95,44 @@ module RASN1
|
|
90
95
|
date_hour << match[2]
|
91
96
|
else
|
92
97
|
# fraction only contains fraction.
|
93
|
-
# Have to add offset with UTC to force
|
94
|
-
# generate a local time.
|
95
|
-
# because of DST.
|
98
|
+
# Have to add offset with UTC to force Strptime to
|
99
|
+
# generate a local time.
|
96
100
|
date_hour << Time.now.strftime('%z')
|
97
|
-
utc_offset_forced = true
|
98
101
|
end
|
99
102
|
|
100
103
|
frac_base = value_from(date_hour)
|
101
|
-
fix_dst if utc_offset_forced
|
102
104
|
fix_value(fraction, frac_base)
|
103
105
|
end
|
104
106
|
|
105
107
|
def value_from(date_hour)
|
106
108
|
format, frac_base = strformat(date_hour)
|
107
|
-
@value =
|
109
|
+
@value = Strptime.new(format).exec(date_hour)
|
108
110
|
frac_base
|
109
111
|
end
|
110
112
|
|
111
|
-
# Check DST. There may be a shift of one hour...
|
112
|
-
def fix_dst
|
113
|
-
compare_time = Time.new(*@value.to_a[0..5].reverse)
|
114
|
-
@value = compare_time if compare_time.utc_offset != @value.utc_offset
|
115
|
-
end
|
116
|
-
|
117
113
|
def fix_value(fraction, frac_base)
|
118
|
-
|
114
|
+
frac = ".#{fraction}".to_r * frac_base
|
115
|
+
@value = (@value + frac) unless fraction.nil?
|
119
116
|
end
|
120
117
|
|
121
|
-
def strformat(date_hour)
|
118
|
+
def strformat(date_hour)
|
122
119
|
case date_hour.size
|
123
120
|
when 11
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
frac_base = 60
|
128
|
-
format = '%Y%m%d%H%MZ'
|
121
|
+
['%Y%m%d%H%z', HOUR_TO_SEC]
|
122
|
+
when 13, 17
|
123
|
+
['%Y%m%d%H%M%z', MINUTE_TO_SEC]
|
129
124
|
when 15
|
130
125
|
if date_hour[-1] == 'Z'
|
131
|
-
|
132
|
-
format = '%Y%m%d%H%M%SZ'
|
126
|
+
['%Y%m%d%H%M%S%z', SECOND_TO_SEC]
|
133
127
|
else
|
134
|
-
|
135
|
-
format = '%Y%m%d%H%z'
|
128
|
+
['%Y%m%d%H%z', HOUR_TO_SEC]
|
136
129
|
end
|
137
|
-
when 17
|
138
|
-
frac_base = 60
|
139
|
-
format = '%Y%m%d%H%M%z'
|
140
130
|
when 19
|
141
|
-
|
142
|
-
format = '%Y%m%d%H%M%S%z'
|
131
|
+
['%Y%m%d%H%M%S%z', SECOND_TO_SEC]
|
143
132
|
else
|
144
133
|
prefix = @name.nil? ? type : "tag #{@name}"
|
145
|
-
raise ASN1Error, "#{prefix}: unrecognized format: #{
|
134
|
+
raise ASN1Error, "#{prefix}: unrecognized format: #{date_hour}"
|
146
135
|
end
|
147
|
-
|
148
|
-
[format, frac_base]
|
149
136
|
end
|
150
137
|
end
|
151
138
|
end
|
@@ -17,12 +17,12 @@ module RASN1
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def value_to_der
|
20
|
-
@value.to_s.force_encoding('US-ASCII').
|
20
|
+
@value.to_s.dup.force_encoding('US-ASCII').b
|
21
21
|
end
|
22
22
|
|
23
23
|
def der_to_value(der, ber: false)
|
24
24
|
super
|
25
|
-
@value.to_s.force_encoding('US-ASCII')
|
25
|
+
@value.to_s.dup.force_encoding('US-ASCII')
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
data/lib/rasn1/types/integer.rb
CHANGED
@@ -133,8 +133,9 @@ module RASN1
|
|
133
133
|
return if @enum.empty?
|
134
134
|
|
135
135
|
int_value = @value
|
136
|
+
raise EnumeratedError, "#{@name}: value #{int_value} not in enumeration" unless @enum.value?(@value)
|
137
|
+
|
136
138
|
@value = @enum.key(@value)
|
137
|
-
raise EnumeratedError, "#{@name}: value #{int_value} not in enumeration" unless value?
|
138
139
|
end
|
139
140
|
|
140
141
|
def explicit_type
|
data/lib/rasn1/types/null.rb
CHANGED
@@ -59,7 +59,6 @@ module RASN1
|
|
59
59
|
Sequence.encoded_type
|
60
60
|
end
|
61
61
|
|
62
|
-
# @param [Symbol, String] name name for this tag in grammar
|
63
62
|
# @param [Class, Base] of_type base type for sequence of
|
64
63
|
# @see Base#initialize
|
65
64
|
def initialize(of_type, options={})
|
@@ -105,6 +104,7 @@ module RASN1
|
|
105
104
|
@value.length
|
106
105
|
end
|
107
106
|
|
107
|
+
# @return [String]
|
108
108
|
def inspect(level=0)
|
109
109
|
str = common_inspect(level)
|
110
110
|
str << "\n"
|
data/lib/rasn1/types/utc_time.rb
CHANGED
@@ -35,20 +35,16 @@ module RASN1
|
|
35
35
|
|
36
36
|
def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
|
37
37
|
format = case der.size
|
38
|
-
when 11
|
39
|
-
'%Y%m%d%H%MZ'
|
40
|
-
when 13
|
41
|
-
'%Y%m%d%H%M%SZ'
|
42
|
-
when 15
|
38
|
+
when 11, 15
|
43
39
|
'%Y%m%d%H%M%z'
|
44
|
-
when 17
|
40
|
+
when 13, 17
|
45
41
|
'%Y%m%d%H%M%S%z'
|
46
42
|
else
|
47
43
|
prefix = @name.nil? ? type : "tag #{@name}"
|
48
44
|
raise ASN1Error, "#{prefix}: unrecognized format: #{der}"
|
49
45
|
end
|
50
46
|
century = (Time.now.year / 100).to_s
|
51
|
-
@value =
|
47
|
+
@value = Strptime.new(format).exec(century + der)
|
52
48
|
end
|
53
49
|
end
|
54
50
|
end
|
@@ -17,12 +17,12 @@ module RASN1
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def value_to_der
|
20
|
-
@value.to_s.force_encoding('UTF-8').
|
20
|
+
@value.to_s.dup.force_encoding('UTF-8').b
|
21
21
|
end
|
22
22
|
|
23
23
|
def der_to_value(der, ber: false)
|
24
24
|
super
|
25
|
-
@value = der.force_encoding('UTF-8')
|
25
|
+
@value = der.dup.force_encoding('UTF-8')
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
data/lib/rasn1/types.rb
CHANGED
@@ -4,18 +4,25 @@ module RASN1
|
|
4
4
|
# This modules is a namesapce for all ASN.1 type classes.
|
5
5
|
# @author Sylvain Daubert
|
6
6
|
module Types
|
7
|
+
@primitives = []
|
8
|
+
@constructed = []
|
9
|
+
|
7
10
|
# Give all primitive types
|
8
11
|
# @return [Array<Types::Primitive>]
|
9
12
|
def self.primitives
|
10
|
-
@primitives
|
11
|
-
|
13
|
+
return @primitives unless @primitives.empty?
|
14
|
+
|
15
|
+
@primitives = self.constants.map { |c| Types.const_get(c) }
|
16
|
+
.select { |klass| klass < Primitive }
|
12
17
|
end
|
13
18
|
|
14
19
|
# Give all constructed types
|
15
20
|
# @return [Array<Types::Constructed>]
|
16
21
|
def self.constructed
|
17
|
-
@constructed
|
18
|
-
|
22
|
+
return @constructed unless @constructed.empty?
|
23
|
+
|
24
|
+
@constructed = self.constants.map { |c| Types.const_get(c) }
|
25
|
+
.select { |klass| klass < Constructed }
|
19
26
|
end
|
20
27
|
|
21
28
|
# @private
|
@@ -67,8 +74,8 @@ module RASN1
|
|
67
74
|
def self.generate_id2type_cache
|
68
75
|
constructed = self.constructed - [Types::SequenceOf, Types::SetOf]
|
69
76
|
primitives = self.primitives - [Types::Enumerated]
|
70
|
-
ary = (primitives + constructed).select { |type| type.const_defined?
|
71
|
-
.map { |type| [type
|
77
|
+
ary = (primitives + constructed).select { |type| type.const_defined?(:ID) }
|
78
|
+
.map { |type| [type.const_get(:ID), type] }
|
72
79
|
@id2types = ary.to_h
|
73
80
|
@id2types.default = Types::Base
|
74
81
|
@id2types.freeze
|
@@ -77,9 +84,12 @@ module RASN1
|
|
77
84
|
# Define a new ASN.1 type from a base one.
|
78
85
|
# This new type may have a constraint defines on it.
|
79
86
|
# @param [Symbol,String] name New type name. Must start with a capital letter.
|
80
|
-
# @param [Types::Base] from
|
87
|
+
# @param [Types::Base] from class from which inherits
|
88
|
+
# @param [Module] in_module module in which creates new type (default to {RASN1::Types})
|
81
89
|
# @return [Class] newly created class
|
82
|
-
|
90
|
+
# @since 0.11.0
|
91
|
+
# @since 0.12.0 in_module parameter
|
92
|
+
def self.define_type(name, from:, in_module: self, &block)
|
83
93
|
constraint = block.nil? ? nil : block.to_proc
|
84
94
|
|
85
95
|
new_klass = Class.new(from) do
|
@@ -87,12 +97,13 @@ module RASN1
|
|
87
97
|
end
|
88
98
|
new_klass.constraint = constraint
|
89
99
|
|
90
|
-
|
91
|
-
|
100
|
+
in_module.const_set(name, new_klass)
|
101
|
+
accel_name = name.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
|
102
|
+
Model.define_type_accel(accel_name, new_klass)
|
92
103
|
|
93
104
|
# Empty type caches
|
94
|
-
@primitives =
|
95
|
-
@constructed =
|
105
|
+
@primitives = []
|
106
|
+
@constructed = []
|
96
107
|
|
97
108
|
new_klass
|
98
109
|
end
|
@@ -108,6 +119,7 @@ require_relative 'types/octet_string'
|
|
108
119
|
require_relative 'types/null'
|
109
120
|
require_relative 'types/object_id'
|
110
121
|
require_relative 'types/enumerated'
|
122
|
+
require_relative 'types/bmp_string'
|
111
123
|
require_relative 'types/utf8_string'
|
112
124
|
require_relative 'types/numeric_string'
|
113
125
|
require_relative 'types/printable_string'
|
data/lib/rasn1/version.rb
CHANGED
@@ -0,0 +1,201 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'delegate'
|
4
|
+
|
5
|
+
module RASN1
|
6
|
+
# This class is used to wrap a {Types::Base} or {Model} instance to force its options.
|
7
|
+
#
|
8
|
+
# == Usage
|
9
|
+
# This class may be used to wrap another RASN1 object by 3 ways:
|
10
|
+
# * wrap an object to modify its options,
|
11
|
+
# * implicitly wrap an object (i.e. change its tag),
|
12
|
+
# * explicitly wrap an object (i.e wrap the object in another explicit ASN.1 tag)
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# # object to wrap
|
16
|
+
# int = RASN1::Types::Integer.new(implicit: 1) # its tag is 0x81
|
17
|
+
# # simple wraper, change an option
|
18
|
+
# wrapper = RASN1::Wrapper.new(int, optional: true, default: 1)
|
19
|
+
# # implicit wrapper
|
20
|
+
# wrapper = RASN1::Wrapper.new(int, implicit: 3) # wrapped int tag is now 0x83
|
21
|
+
# # explicit wrapper
|
22
|
+
# wrapper = RASN1::Wrapper.new(int, explicit: 4) # int tag is always 0x81, but it is wrapped in a 0x84 tag
|
23
|
+
# @since 0.12.0
|
24
|
+
class Wrapper < SimpleDelegator
|
25
|
+
# @private Private class used to build/parse explicit wrappers
|
26
|
+
class ExplicitWrapper < Types::Base
|
27
|
+
ID = 0 # not used
|
28
|
+
ASN1_PC = 0 # not constructed
|
29
|
+
|
30
|
+
def self.type
|
31
|
+
''
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Boolean]
|
35
|
+
# @see Types::Base#can_build?
|
36
|
+
def can_build?
|
37
|
+
ok = super
|
38
|
+
return ok unless optional?
|
39
|
+
|
40
|
+
ok && @value.can_build?
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def value_to_der
|
46
|
+
@value.is_a?(String) ? @value : @value.to_der
|
47
|
+
end
|
48
|
+
|
49
|
+
def inspect_value
|
50
|
+
''
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# @param [Types::Base,Model] element element to wrap
|
55
|
+
# @param [Hash] options
|
56
|
+
def initialize(element, options={})
|
57
|
+
opts = explicit_implicit(options)
|
58
|
+
|
59
|
+
if explicit?
|
60
|
+
generate_explicit_wrapper(opts)
|
61
|
+
element.options = element.options.merge(generate_explicit_wrapper_options(opts))
|
62
|
+
@options = opts
|
63
|
+
else
|
64
|
+
opts[:value] = element.value
|
65
|
+
element.options = element.options.merge(opts)
|
66
|
+
@options = {}
|
67
|
+
end
|
68
|
+
raise RASN1::Error, 'Cannot be implicit and explicit' if explicit? && implicit?
|
69
|
+
|
70
|
+
super(element)
|
71
|
+
end
|
72
|
+
|
73
|
+
def explicit_implicit(options)
|
74
|
+
opts = options.dup
|
75
|
+
@explicit = opts.delete(:explicit)
|
76
|
+
@implicit = opts.delete(:implicit)
|
77
|
+
opts
|
78
|
+
end
|
79
|
+
|
80
|
+
def generate_explicit_wrapper(options)
|
81
|
+
# ExplicitWrapper is a hand-made explicit tag, but we have to use its implicit option
|
82
|
+
# to force its tag value.
|
83
|
+
@explicit_wrapper = ExplicitWrapper.new(options.merge(implicit: @explicit))
|
84
|
+
end
|
85
|
+
|
86
|
+
def generate_explicit_wrapper_options(options)
|
87
|
+
new_opts = {}
|
88
|
+
new_opts[:default] = options[:default] if options.key?(:default)
|
89
|
+
new_opts[:optional] = options[:optional] if options.key?(:optional)
|
90
|
+
new_opts
|
91
|
+
end
|
92
|
+
|
93
|
+
# Say if wrapper is an explicit one (i.e. add tag and length to its element)
|
94
|
+
# @return [Boolean]
|
95
|
+
def explicit?
|
96
|
+
!!@explicit
|
97
|
+
end
|
98
|
+
|
99
|
+
# Say if wrapper is an implicit one (i.e. change tag of its element)
|
100
|
+
# @return [Boolean]
|
101
|
+
def implicit?
|
102
|
+
!!@implicit
|
103
|
+
end
|
104
|
+
|
105
|
+
# Convert wrapper and its element to a DER string
|
106
|
+
# @return [String]
|
107
|
+
def to_der
|
108
|
+
if implicit?
|
109
|
+
el = generate_implicit_element
|
110
|
+
el.to_der
|
111
|
+
elsif explicit?
|
112
|
+
@explicit_wrapper.value = element
|
113
|
+
@explicit_wrapper.to_der
|
114
|
+
else
|
115
|
+
element.to_der
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Parse a DER string. This method updates object.
|
120
|
+
# @param [String] der DER string
|
121
|
+
# @param [Boolean] ber if +true+, accept BER encoding
|
122
|
+
# @return [Integer] total number of parsed bytes
|
123
|
+
# @raise [ASN1Error] error on parsing
|
124
|
+
def parse!(der, ber: false)
|
125
|
+
if implicit?
|
126
|
+
el = generate_implicit_element
|
127
|
+
parsed = el.parse!(der, ber: ber)
|
128
|
+
element.value = el.value
|
129
|
+
parsed
|
130
|
+
elsif explicit?
|
131
|
+
parsed = @explicit_wrapper.parse!(der, ber: ber)
|
132
|
+
element.parse!(@explicit_wrapper.value, ber: ber) if parsed.positive?
|
133
|
+
parsed
|
134
|
+
else
|
135
|
+
element.parse!(der, ber: ber)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def value?
|
140
|
+
if explicit?
|
141
|
+
@explicit_wrapper.value?
|
142
|
+
else
|
143
|
+
__getobj__.value?
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Return Wrapped element
|
148
|
+
# @return [Types::Base,Model]
|
149
|
+
def element
|
150
|
+
__getobj__
|
151
|
+
end
|
152
|
+
|
153
|
+
# @return [::Integer]
|
154
|
+
def id
|
155
|
+
if implicit?
|
156
|
+
@implicit
|
157
|
+
elsif explicit?
|
158
|
+
@explicit
|
159
|
+
else
|
160
|
+
element.id
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# @return [Symbol]
|
165
|
+
def asn1_class
|
166
|
+
return element.asn1_class unless @options.key?(:class)
|
167
|
+
|
168
|
+
@options[:class]
|
169
|
+
end
|
170
|
+
|
171
|
+
# @return [Boolean]
|
172
|
+
def constructed?
|
173
|
+
return element.constructed? unless @options.key?(:constructed)
|
174
|
+
|
175
|
+
@options[:constructed]
|
176
|
+
end
|
177
|
+
|
178
|
+
# @return [Boolean]
|
179
|
+
def primitive?
|
180
|
+
!constructed?
|
181
|
+
end
|
182
|
+
|
183
|
+
def inspect(level=0)
|
184
|
+
return super(level) unless explicit?
|
185
|
+
|
186
|
+
@explicit_wrapper.inspect(level) << ' ' << super(level)
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
def generate_implicit_element
|
192
|
+
el = element.dup
|
193
|
+
if el.explicit?
|
194
|
+
el.options = el.options.merge(explicit: @implicit)
|
195
|
+
elsif el.implicit?
|
196
|
+
el.options = el.options.merge(implicit: @implicit)
|
197
|
+
end
|
198
|
+
el
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
data/lib/rasn1.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
require_relative 'rasn1/version'
|
4
|
+
require_relative 'rasn1/errors'
|
5
|
+
require_relative 'rasn1/types'
|
6
|
+
require_relative 'rasn1/model'
|
7
|
+
require_relative 'rasn1/wrapper'
|
7
8
|
|
8
9
|
# Rasn1 is a pure ruby library to parse, decode and encode ASN.1 data.
|
9
10
|
# @author Sylvain Daubert
|
metadata
CHANGED
@@ -1,57 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rasn1
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.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: 2022-
|
11
|
+
date: 2022-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: strptime
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
-
type: :
|
19
|
+
version: 0.2.5
|
20
|
+
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rspec
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '3.0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '3.0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: yard
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0.9'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0.9'
|
26
|
+
version: 0.2.5
|
55
27
|
description: |
|
56
28
|
RASN1 is a pure ruby ASN.1 library. It may encode and decode DER and BER
|
57
29
|
encodings.
|
@@ -72,6 +44,7 @@ files:
|
|
72
44
|
- lib/rasn1/types/any.rb
|
73
45
|
- lib/rasn1/types/base.rb
|
74
46
|
- lib/rasn1/types/bit_string.rb
|
47
|
+
- lib/rasn1/types/bmp_string.rb
|
75
48
|
- lib/rasn1/types/boolean.rb
|
76
49
|
- lib/rasn1/types/choice.rb
|
77
50
|
- lib/rasn1/types/constrained.rb
|
@@ -94,6 +67,7 @@ files:
|
|
94
67
|
- lib/rasn1/types/utf8_string.rb
|
95
68
|
- lib/rasn1/types/visible_string.rb
|
96
69
|
- lib/rasn1/version.rb
|
70
|
+
- lib/rasn1/wrapper.rb
|
97
71
|
homepage: https://github.com/sdaubert/rasn1
|
98
72
|
licenses:
|
99
73
|
- MIT
|