rasn1 0.16.1 → 0.16.3

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.
data/lib/rasn1/tracer.rb CHANGED
@@ -14,23 +14,25 @@ module RASN1
14
14
  # @return [Integer]
15
15
  attr_accessor :tracing_level
16
16
 
17
+ # @private
18
+ # Classes to trace
17
19
  TRACED_CLASSES = [Types::Any, Types::Choice, Types::Sequence, Types::SequenceOf, Types::Base].freeze
18
20
 
19
- # @param [IO] io
21
+ # @param io [IO] io to use to put traces
20
22
  def initialize(io)
21
23
  @io = io
22
24
  @tracing_level = 0
23
25
  end
24
26
 
25
27
  # Puts +msg+ onto {#io}.
26
- # @param [String] msg
28
+ # @param msg [String]
27
29
  # @return [void]
28
30
  def trace(msg)
29
31
  @io.puts(indent << msg)
30
32
  end
31
33
 
32
34
  # Return identation for given +level+. If +nil+, use {#tracing_level}.
33
- # @param [Integer,nil] level
35
+ # @param level [Integer,nil]
34
36
  # @return [String]
35
37
  def indent(level=nil)
36
38
  level ||= @tracing_level
@@ -41,13 +43,13 @@ module RASN1
41
43
  # Trace RASN1 parsing to +io+.
42
44
  # All parsing methods called in block are traced to +io+. Each ASN.1 element is
43
45
  # traced in a line showing element's id, its length and its data.
44
- # @param [IO] io
46
+ # @param io [IO]
47
+ # @return [void]
45
48
  # @example
46
49
  # RASN1.trace do
47
50
  # RASN1.parse("\x02\x01\x01") # puts "INTEGER id: 2 (0x02), len: 1 (0x01), data: 0x01"
48
51
  # end
49
52
  # RASN1.parse("\x01\x01\xff") # puts nothing onto STDOUT
50
- # @return [void]
51
53
  def self.trace(io=$stdout)
52
54
  @tracer = Tracer.new(io)
53
55
  Tracer::TRACED_CLASSES.each(&:start_tracing)
@@ -62,6 +64,7 @@ module RASN1
62
64
  end
63
65
 
64
66
  # @private
67
+ # @return [Tracer]
65
68
  def self.tracer
66
69
  @tracer
67
70
  end
@@ -71,6 +74,7 @@ module RASN1
71
74
  class << self
72
75
  # @private
73
76
  # Patch {#do_parse} to add tracing ability
77
+ # @return [void]
74
78
  def start_tracing
75
79
  alias_method :do_parse_without_tracing, :do_parse
76
80
  alias_method :do_parse, :do_parse_with_tracing
@@ -80,6 +84,7 @@ module RASN1
80
84
 
81
85
  # @private
82
86
  # Unpatch {#do_parse} to remove tracing ability
87
+ # @return [void]
83
88
  def stop_tracing
84
89
  alias_method :do_parse, :do_parse_without_tracing
85
90
  alias_method :do_parse_explicit, :do_parse_explicit_without_tracing
@@ -88,6 +93,7 @@ module RASN1
88
93
 
89
94
  # @private
90
95
  # Parse +der+ with tracing abillity
96
+ # @!macro do_parse
91
97
  # @see #parse!
92
98
  def do_parse_with_tracing(der, ber:)
93
99
  ret = do_parse_without_tracing(der, ber: ber)
@@ -95,6 +101,11 @@ module RASN1
95
101
  ret
96
102
  end
97
103
 
104
+ # @private
105
+ # Delegate with tracing to explicit type to generate sub-value
106
+ # @param data [String]
107
+ # @return [void]
108
+ # @see #parse!
98
109
  def do_parse_explicit_with_tracing(data)
99
110
  RASN1.tracer.tracing_level += 1
100
111
  do_parse_explicit_without_tracing(data)
@@ -106,6 +117,7 @@ module RASN1
106
117
  class << self
107
118
  # @private
108
119
  # Patch {#parse!} to add tracing ability
120
+ # @return [void]
109
121
  def start_tracing
110
122
  alias_method :parse_without_tracing, :parse!
111
123
  alias_method :parse!, :parse_with_tracing
@@ -113,6 +125,7 @@ module RASN1
113
125
 
114
126
  # @private
115
127
  # Unpatch {#parse!} to remove tracing ability
128
+ # @return [void]
116
129
  def stop_tracing
117
130
  alias_method :parse!, :parse_without_tracing
118
131
  end
@@ -120,6 +133,7 @@ module RASN1
120
133
 
121
134
  # @private
122
135
  # Parse +der+ with tracing abillity
136
+ # @!macro do_parse
123
137
  # @see #parse!
124
138
  def parse_with_tracing(der, ber: false)
125
139
  RASN1.tracer.trace(self.trace)
@@ -131,6 +145,7 @@ module RASN1
131
145
  class << self
132
146
  # @private
133
147
  # Patch {#der_to_value} to add tracing ability
148
+ # @return [void]
134
149
  def start_tracing
135
150
  alias_method :der_to_value_without_tracing, :der_to_value
136
151
  alias_method :der_to_value, :der_to_value_with_tracing
@@ -138,6 +153,7 @@ module RASN1
138
153
 
139
154
  # @private
140
155
  # Unpatch {#der_to_value} to remove tracing ability
156
+ # @return [void]
141
157
  def stop_tracing
142
158
  alias_method :der_to_value, :der_to_value_without_tracing
143
159
  end
@@ -145,6 +161,7 @@ module RASN1
145
161
 
146
162
  # @private
147
163
  # der_to_value +der+ with tracing abillity
164
+ # @!macro do_parse
148
165
  def der_to_value_with_tracing(der, ber: false)
149
166
  RASN1.tracer.tracing_level += 1
150
167
  der_to_value_without_tracing(der, ber: ber)
@@ -156,6 +173,7 @@ module RASN1
156
173
  class << self
157
174
  # @private
158
175
  # Patch {#der_to_value} to add tracing ability
176
+ # @return [void]
159
177
  def start_tracing
160
178
  alias_method :der_to_value_without_tracing, :der_to_value
161
179
  alias_method :der_to_value, :der_to_value_with_tracing
@@ -163,6 +181,7 @@ module RASN1
163
181
 
164
182
  # @private
165
183
  # Unpatch {#der_to_value} to remove tracing ability
184
+ # @return [void]
166
185
  def stop_tracing
167
186
  alias_method :der_to_value, :der_to_value_without_tracing
168
187
  end
@@ -170,6 +189,7 @@ module RASN1
170
189
 
171
190
  # @private
172
191
  # der_to_value +der+ with tracing abillity
192
+ # @!macro do_parse
173
193
  def der_to_value_with_tracing(der, ber: false)
174
194
  RASN1.tracer.tracing_level += 1
175
195
  der_to_value_without_tracing(der, ber: ber)
@@ -10,7 +10,24 @@ module RASN1
10
10
  module Types
11
11
  # ASN.1 ANY: accepts any types
12
12
  #
13
+ # ANY is often used with an {ObjectId} to detect real type.
14
+ #
15
+ # On encoding, ANY is replaced by its values (which must be an RASN1 type).
13
16
  # If `any#value` is `nil` and Any object is not {#optional?}, `any` will be encoded as a {Null} object.
17
+ #
18
+ # @example Parsing with any model
19
+ # class AnyModel < RASN1::Model
20
+ # sequence :seq,
21
+ # content: [objectid(:id), any(:data)]
22
+ # end
23
+ # model = AnyModel.new
24
+ # model.parse!("\x30\x09\x06\x03\x2a\x03\x04\x02\x02\x01\xff")
25
+ # model[:id].value #=> "1.2.3.4"
26
+ # model[:data].value #=> "\x02\x02\x01\xff"
27
+ # # As we knwon object with id 1.2.3.4 is an integer, with then parse data as such
28
+ # data = RASN1::Types::Integer.new
29
+ # data.parse!(model[:data].value)
30
+ # data.value #=> 511
14
31
  # @author Sylvain Daubert
15
32
  class Any < Base
16
33
  # @return [String] DER-formated string
@@ -27,21 +44,22 @@ module RASN1
27
44
  end
28
45
  end
29
46
 
47
+ # @return [Boolean]
30
48
  def can_build?
31
49
  value? || !optional?
32
50
  end
33
51
 
34
52
  # Parse a DER string. This method updates object: {#value} will be a DER
35
53
  # string.
36
- # @param [String] der DER string
37
- # @param [Boolean] ber if +true+, accept BER encoding
54
+ # @param der [String] DER string
55
+ # @param ber [Boolean] if +true+, accept BER encoding
38
56
  # @return [Integer] total number of parsed bytes
39
57
  def parse!(der, ber: false)
40
58
  total_length, _data = do_parse(der, ber: ber)
41
59
  total_length
42
60
  end
43
61
 
44
- # @param [::Integer] level
62
+ # @param level [::Integer]
45
63
  # @return [String]
46
64
  def inspect(level=0)
47
65
  str = common_inspect(level)
@@ -66,6 +84,7 @@ module RASN1
66
84
 
67
85
  private
68
86
 
87
+ # @param level [Integer]
69
88
  def common_inspect(level)
70
89
  lvl = [0, level].max
71
90
  str = ' ' * lvl
@@ -77,6 +96,7 @@ module RASN1
77
96
  end
78
97
 
79
98
  # @private
99
+ # @!macro do_parse
80
100
  # @see Types::Base#do_parse
81
101
  def do_parse(der, ber: false)
82
102
  if der.empty?
@@ -96,6 +116,7 @@ module RASN1
96
116
  [total_length, real_value]
97
117
  end
98
118
 
119
+ # @return [String]
99
120
  def trace_any
100
121
  msg_type(no_id: true) << trace_data(value)
101
122
  end
@@ -75,7 +75,7 @@ module RASN1
75
75
  attr_reader :asn1_class
76
76
  # @return [Object,nil] default value, if defined
77
77
  attr_reader :default
78
- # @return [Hash[Symbol, Object]]
78
+ # @return [Hash{Symbol => Object}]
79
79
  attr_reader :options
80
80
  # @return [String] raw parsed data
81
81
  attr_reader :raw_data
@@ -99,10 +99,10 @@ module RASN1
99
99
  end
100
100
 
101
101
  # Parse a DER or BER string
102
- # @param [String] der_or_ber string to parse
103
- # @param [Hash] options
104
- # @return [Base]
102
+ # @param der_or_ber [String] string to parse
103
+ # @param options [Hash]
105
104
  # @option options [Boolean] :ber if +true+, parse a BER string, else a DER one
105
+ # @return [Base]
106
106
  # @note More options are supported. See {Base#initialize}.
107
107
  def self.parse(der_or_ber, options={})
108
108
  obj = self.new(options)
@@ -117,18 +117,19 @@ module RASN1
117
117
  false
118
118
  end
119
119
 
120
- # @param [Hash] options
121
- # @option options [Symbol] :class ASN.1 class. Default value is +:universal+.
122
- # If +:explicit+ or +:implicit:+ is defined, default value is +:context+.
123
- # @option options [::Boolean] :optional define this tag as optional. Default
124
- # is +false+
125
- # @option options [Object] :default default value (ASN.1 DEFAULT)
126
- # @option options [Object] :value value to set
127
- # @option options [::Integer] :implicit define an IMPLICIT tagged type
128
- # @option options [::Integer] :explicit define an EXPLICIT tagged type
129
- # @option options [::Boolean] :constructed if +true+, set type as constructed.
130
- # May only be used when +:explicit+ is defined, else it is discarded.
131
- # @option options [::String] :name name for this node
120
+ # @!macro [new] type_initialize
121
+ # @param options [Hash]
122
+ # @option options [Symbol] :class ASN.1 class. Default value is +:universal+.
123
+ # If +:explicit+ or +:implicit:+ is defined, default value is +:context+.
124
+ # @option options [::Boolean] :optional define this tag as optional. Default
125
+ # is +false+
126
+ # @option options [Object] :default default value (ASN.1 DEFAULT)
127
+ # @option options [Object] :value value to set
128
+ # @option options [::Integer] :implicit define an IMPLICIT tagged type
129
+ # @option options [::Integer] :explicit define an EXPLICIT tagged type
130
+ # @option options [::Boolean] :constructed if +true+, set type as constructed.
131
+ # May only be used when +:explicit+ is defined, else it is discarded.
132
+ # @option options [::String] :name name for this node
132
133
  def initialize(options={})
133
134
  @constructed = nil
134
135
  set_value(options.delete(:value))
@@ -142,6 +143,7 @@ module RASN1
142
143
  def specific_initializer; end
143
144
 
144
145
  # Deep copy @value and @default.
146
+ # @return [void]
145
147
  def initialize_copy(*)
146
148
  super
147
149
  @value = @value.dup
@@ -150,6 +152,7 @@ module RASN1
150
152
  end
151
153
 
152
154
  # Get value or default value
155
+ # @return [Object]
153
156
  def value
154
157
  if value?
155
158
  @value
@@ -159,12 +162,16 @@ module RASN1
159
162
  end
160
163
 
161
164
  # Set value. If +val+ is +nil+, unset value
162
- # @param [Object,nil] val
165
+ # @!macro [new] value_setter
166
+ # @param val [Object,nil]
167
+ # @return [Object] return +val+
163
168
  def value=(val)
164
169
  set_value(val)
165
170
  end
166
171
 
167
172
  # @abstract Define 'void' value (i.e. 'value' when no value was set)
173
+ # For base type, this is an empty string
174
+ # @return [Object]
168
175
  def void_value
169
176
  ''
170
177
  end
@@ -202,11 +209,13 @@ module RASN1
202
209
  build
203
210
  end
204
211
 
212
+ # Say if self is defined as primitive (subclass of {Primitive} and constructed not defined in tag)
205
213
  # @return [::Boolean] +true+ if this is a primitive type
206
214
  def primitive?
207
215
  (self.class < Primitive) && !@constructed
208
216
  end
209
217
 
218
+ # Say if self is defined as constructed (subclass of {Constructed} or constructed defined in tag)
210
219
  # @return [::Boolean] +true+ if this is a constructed type
211
220
  def constructed?
212
221
  (self.class < Constructed) || !!@constructed
@@ -227,8 +236,8 @@ module RASN1
227
236
  # @abstract This method SHOULD be partly implemented by subclasses to parse
228
237
  # data. Subclasses SHOULD respond to +#der_to_value+.
229
238
  # Parse a DER string. This method updates object.
230
- # @param [String] der DER string
231
- # @param [Boolean] ber if +true+, accept BER encoding
239
+ # @param der [String] DER string
240
+ # @param ber [Boolean] if +true+, accept BER encoding
232
241
  # @return [Integer] total number of parsed bytes
233
242
  # @raise [ASN1Error] error on parsing
234
243
  def parse!(der, ber: false)
@@ -250,7 +259,7 @@ module RASN1
250
259
  value_to_der.size
251
260
  end
252
261
 
253
- # @param [Integer] level
262
+ # @param level [Integer]
254
263
  # @return [String]
255
264
  def inspect(level=0)
256
265
  str = common_inspect(level)
@@ -261,14 +270,14 @@ module RASN1
261
270
  end
262
271
 
263
272
  # Objects are equal if they have same class AND same DER
264
- # @param [Base] other
273
+ # @param other [Base]
265
274
  # @return [Boolean]
266
275
  def ==(other)
267
276
  (other.class == self.class) && (other.to_der == self.to_der)
268
277
  end
269
278
 
270
279
  # Set options to this object
271
- # @param [Hash] options
280
+ # @param options [Hash]
272
281
  # @return [void]
273
282
  # @since 0.12
274
283
  def options=(options)
@@ -307,10 +316,12 @@ module RASN1
307
316
  end
308
317
  end
309
318
 
310
- # @private Parse tage and length from binary string. Return data length and binary data.
311
- # @param [String] der
312
- # @param [Boolean] ber
313
- # @return [Array(::Integer, String)]
319
+ # @private
320
+ # Parse tage and length from binary string. Return data length and binary data.
321
+ # @!macro [new] do_parse
322
+ # @param der [String]
323
+ # @param ber [Boolean]
324
+ # @return [Array(::Integer, String)]
314
325
  # @since 0.15.0 was private before
315
326
  def do_parse(der, ber: false)
316
327
  return [0, ''] unless check_id(der)
@@ -323,8 +334,9 @@ module RASN1
323
334
  [total_length, data]
324
335
  end
325
336
 
326
- # @private Delegate to #explicit type to generate sub-value
327
- # @param [String] data
337
+ # @private
338
+ # Delegate to explicit type to generate sub-value
339
+ # @param data [String]
328
340
  # @return [void]
329
341
  # @since 0.15.0 was private before
330
342
  def do_parse_explicit(data)
@@ -334,8 +346,8 @@ module RASN1
334
346
  end
335
347
 
336
348
  # Make value from DER/BER string
337
- # @param [String] der
338
- # @param [::Boolean] ber
349
+ # @param der [String]
350
+ # @param ber [::Boolean]
339
351
  # @return [void]
340
352
  # @since 0.15.0 was private before
341
353
  def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
@@ -344,16 +356,21 @@ module RASN1
344
356
 
345
357
  private
346
358
 
359
+ # @private Tracer private API
360
+ # @return [String]
347
361
  def trace_real
348
- encoded_id = unpack(encode_identifier_octets)
362
+ encoded_id = bin2hex(encode_identifier_octets)
349
363
  data_length = raw_data.length
350
- encoded_length = unpack(raw_length)
364
+ encoded_length = bin2hex(raw_length)
351
365
  msg = msg_type
352
366
  msg << " (0x#{encoded_id}),"
353
367
  msg << " len: #{data_length} (0x#{encoded_length})"
354
368
  msg << trace_data
355
369
  end
356
370
 
371
+ # @private Tracer private API
372
+ # @param data [String,nil]
373
+ # @return [String]
357
374
  def trace_data(data=nil)
358
375
  byte_count = 0
359
376
  data ||= raw_data
@@ -372,24 +389,33 @@ module RASN1
372
389
  lines.map(&:rstrip).join << "\n"
373
390
  end
374
391
 
392
+ # @private Tracer private API
393
+ # @param count [Integer]
394
+ # @return [String]
375
395
  def trace_format_new_data_line(count)
376
396
  head_line = RASN1.tracer.indent(RASN1.tracer.tracing_level + 1)
377
397
  ("\n#{head_line}%04x " % count) << ' ' * 68
378
398
  end
379
399
 
400
+ # @private Tracer private API
401
+ # @param byte_count [Integer]
402
+ # @param byte_count_mul [Integer]
403
+ # @param offset [Integer]
404
+ # @return [Integer]
380
405
  def compute_trace_index(byte_count, byte_count_mul=1, offset=0)
381
406
  base_idx = 7 + RASN1.tracer.indent(RASN1.tracer.tracing_level + 1).length
382
407
  base_idx + offset + (byte_count % 16) * byte_count_mul
383
408
  end
384
409
 
385
- def unpack(binstr)
386
- binstr.unpack1('H*')
387
- end
388
-
410
+ # Give ASN.1 tag class as a string. Universal class is returned as an empty string.
411
+ # @return [String]
389
412
  def asn1_class_to_s
390
413
  asn1_class == :universal ? '' : asn1_class.to_s.upcase << ' '
391
414
  end
392
415
 
416
+ # @private Tracer private API
417
+ # @param no_id [Boolean] if +true+, do not show id
418
+ # @return [String]
393
419
  def msg_type(no_id: false)
394
420
  msg = name.nil? ? +'' : "#{name} "
395
421
  msg << "[ #{asn1_class_to_s}#{id} ] " unless no_id
@@ -405,6 +431,8 @@ module RASN1
405
431
  msg
406
432
  end
407
433
 
434
+ # Return a byte with P/C bit set accordingly to self
435
+ # @return [Integer]
408
436
  def pc_bit
409
437
  if @constructed.nil?
410
438
  self.class.const_get(:ASN1_PC)
@@ -415,6 +443,9 @@ module RASN1
415
443
  end
416
444
  end
417
445
 
446
+ # Common part for {#inspect}
447
+ # @param level [Integer]
448
+ # @return [String]
418
449
  def common_inspect(level)
419
450
  lvl = [level, 0].max
420
451
  str = ' ' * lvl
@@ -425,6 +456,8 @@ module RASN1
425
456
  str << "#{type}:"
426
457
  end
427
458
 
459
+ # Value part for {#inspect}
460
+ # @return [String]
428
461
  def inspect_value
429
462
  if value?
430
463
  value.inspect
@@ -433,6 +466,8 @@ module RASN1
433
466
  end
434
467
  end
435
468
 
469
+ # Serialize value to DER encoding
470
+ # @return [String]
436
471
  def value_to_der
437
472
  case @value
438
473
  when Base
@@ -442,6 +477,10 @@ module RASN1
442
477
  end
443
478
  end
444
479
 
480
+ # Set class
481
+ # @param asn1_class [Symbol, nil]
482
+ # @return [Symbol] ASN.1 symbol class from {CLASSES}
483
+ # @raise [ClassError]
445
484
  def set_class(asn1_class) # rubocop:disable Naming/AccessorMethodName
446
485
  case asn1_class
447
486
  when nil
@@ -455,16 +494,28 @@ module RASN1
455
494
  end
456
495
  end
457
496
 
497
+ # Set @optional
498
+ # @param optional [Object]
499
+ # @return [Boolean]
458
500
  def set_optional(optional) # rubocop:disable Naming/AccessorMethodName
459
501
  @optional = !!optional
460
502
  end
461
503
 
504
+ # Set @default
505
+ # @param default [Object] default value to set
506
+ # @return [Object] +default+
462
507
  def set_default(default) # rubocop:disable Naming/AccessorMethodName
463
508
  @default = default
464
509
  end
465
510
 
466
511
  # handle undocumented option +:tag_value+, used internally by
467
512
  # {RASN1.parse} to parse non-universal class tags.
513
+ # @param options [Hash]
514
+ # @option options [Boolean] :constructed
515
+ # @option options [Integer] :explicit
516
+ # @option options [Integer] :implicit
517
+ # @option options [Integer] :tag_value
518
+ # @return [void]
468
519
  def set_tag(options) # rubocop:disable Naming/AccessorMethodName
469
520
  @constructed = options[:constructed]
470
521
  if options[:explicit]
@@ -480,6 +531,9 @@ module RASN1
480
531
  @asn1_class = :context if defined?(@tag) && (@asn1_class == :universal)
481
532
  end
482
533
 
534
+ # Set value
535
+ # @param value [Object]
536
+ # @return [Object] +value+ or {#void_value} if +value+ is +nil
483
537
  def set_value(value) # rubocop:disable Naming/AccessorMethodName
484
538
  if value.nil?
485
539
  @no_value = true
@@ -491,6 +545,8 @@ module RASN1
491
545
  value
492
546
  end
493
547
 
548
+ # Encode +self+ to BER encoding
549
+ # @return [String]
494
550
  def build
495
551
  if can_build?
496
552
  if explicit?
@@ -506,16 +562,22 @@ module RASN1
506
562
  end
507
563
  end
508
564
 
565
+ # Return ID part of tag
566
+ # @return [Integer]
509
567
  def id_value
510
568
  return @id_value if defined?(@id_value) && !@id_value.nil?
511
569
 
512
570
  self.class.const_get(:ID)
513
571
  end
514
572
 
573
+ # Encode ID
574
+ # @return [String]
515
575
  def encode_identifier_octets
516
576
  id2octets.pack('C*')
517
577
  end
518
578
 
579
+ # Generate an aray of bytes from ID
580
+ # @return [Array<Integer>]
519
581
  def id2octets
520
582
  first_octet = CLASSES[asn1_class] | pc_bit
521
583
  if id < MULTI_OCTETS_ID
@@ -528,6 +590,8 @@ module RASN1
528
590
  # Encode an unsigned integer on multiple octets.
529
591
  # Value is encoded on bit 6-0 of each octet, bit 7(MSB) indicates wether
530
592
  # further octets follow.
593
+ # @param value [Integer]
594
+ # @return [Array<Integer>]
531
595
  def unsigned_to_chained_octets(value)
532
596
  ary = []
533
597
  while value.positive?
@@ -538,6 +602,9 @@ module RASN1
538
602
  ary
539
603
  end
540
604
 
605
+ # Encode size to bytes
606
+ # @param size [integer]
607
+ # @return [String]
541
608
  def encode_size(size)
542
609
  if size >= INDEFINITE_LENGTH
543
610
  bytes = []
@@ -554,6 +621,7 @@ module RASN1
554
621
  end
555
622
 
556
623
  # Check ID from +der+ is the one expected
624
+ # @param der [String] DER binary data
557
625
  # @return [Boolean] +true+ is ID is expected, +false+ if it is not but +self+ is {#optional?}
558
626
  # or has a {#default} value.
559
627
  # @raise [ASN1Error] ID was not expected, is not optional and has no default value
@@ -573,6 +641,10 @@ module RASN1
573
641
  false
574
642
  end
575
643
 
644
+ # Extract data from DER/BER binary string
645
+ # @param der [String]
646
+ # @param ber [Boolean] +false+ => DER encoding, +true+ => BER encoding
647
+ # @return [Array(Integer, String)] Tuple of total element length in bytes and its data
576
648
  def get_data(der, ber)
577
649
  return [0, ''] if der.nil? || der.empty?
578
650
 
@@ -588,6 +660,10 @@ module RASN1
588
660
  [total_length, data]
589
661
  end
590
662
 
663
+ # Extract length of element from DER/BER binary string
664
+ # @param der [String]
665
+ # @param ber [Boolean] +false+ => DER encoding, +true+ => BER encoding
666
+ # @return [Array(Integer, Integer)] Tuple of length of data and length of length field, in bytes
591
667
  def get_length(der, ber)
592
668
  length = der.unpack1('C').to_i
593
669
  length_length = 0
@@ -603,6 +679,9 @@ module RASN1
603
679
  [length, length_length]
604
680
  end
605
681
 
682
+ # @param ber [Boolean] +false+ => DER encoding, +true+ => BER encoding
683
+ # @raise [ASN1Error] indefinite length and primitive type or DER encoding
684
+ # @raise [NotImplementedError] indefinite length and BER encoding
606
685
  def raise_on_indefinite_length(ber)
607
686
  if primitive?
608
687
  raise ASN1Error, "malformed #{type}: indefinite length " \
@@ -614,16 +693,24 @@ module RASN1
614
693
  end
615
694
  end
616
695
 
696
+ # Return a new object of explicit type class
697
+ # @return [Types::Base]
617
698
  def explicit_type
618
699
  self.class.new(name: name)
619
700
  end
620
701
 
702
+ # Raise bad id error
703
+ # @param der [String] DER/BER data
704
+ # @return [void]
705
+ # @raise [ASN1Error]
621
706
  def raise_id_error(der)
622
707
  msg = name.nil? ? +'' : "#{name}: "
623
708
  msg << "Expected #{self2name} but get #{der2name(der)}"
624
709
  raise ASN1Error, msg
625
710
  end
626
711
 
712
+ # Return human-readable tag name for self
713
+ # @return [String]
627
714
  def self2name
628
715
  name = "#{asn1_class.to_s.upcase} #{constructed? ? 'CONSTRUCTED' : 'PRIMITIVE'}"
629
716
  if implicit? || explicit?
@@ -633,6 +720,9 @@ module RASN1
633
720
  end
634
721
  end
635
722
 
723
+ # Return human-readable tag name for given +der+
724
+ # @param der [String] DER/BER data
725
+ # @return [String]
636
726
  def der2name(der)
637
727
  return 'no ID' if der.nil? || der.empty?
638
728
 
@@ -642,12 +732,18 @@ module RASN1
642
732
  name << " #{type.nil? ? '0x%X (0x%s)' % [id, bin2hex(der[0...id_size])] : type.encoded_type}"
643
733
  end
644
734
 
735
+ # Return RASN1 class associated with +id+
736
+ # @param id [Integer]
737
+ # @return [Class,nil]
645
738
  def find_type(id)
646
739
  Types.constants.map { |c| Types.const_get(c) }
647
740
  .select { |klass| klass < Primitive || klass < Constructed }
648
741
  .find { |klass| id == klass::ID }
649
742
  end
650
743
 
744
+ # Unpack given binary string to hex string
745
+ # @param str [String] binary string
746
+ # @return [String] hex string
651
747
  def bin2hex(str)
652
748
  str.unpack1('H*')
653
749
  end