rasn1 0.14.0 → 0.16.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.
@@ -6,8 +6,8 @@ module RASN1
6
6
  #
7
7
  # Subclasses SHOULD define:
8
8
  # * an ID constant defining ASN.1 BER/DER identification number,
9
+ # * a method {#der_to_value} converting DER into {#value}.
9
10
  # * a private method {#value_to_der} converting its {#value} to DER,
10
- # * a private method {#der_to_value} converting DER into {#value}.
11
11
  #
12
12
  # ==Define an optional value
13
13
  # An optional value may be defined using +:optional+ key from {#initialize}:
@@ -178,14 +178,14 @@ module RASN1
178
178
  # @return [::Boolean,nil] return +nil+ if not tagged, return +true+
179
179
  # if explicit, else +false+
180
180
  def explicit?
181
- defined?(@tag) ? @tag == :explicit : nil
181
+ defined?(@tag) ? @tag == :explicit : nil # rubocop:disable Style/ReturnNilInPredicateMethodDefinition
182
182
  end
183
183
 
184
184
  # Say if a tagged type is implicit
185
185
  # @return [::Boolean,nil] return +nil+ if not tagged, return +true+
186
186
  # if implicit, else +false+
187
187
  def implicit?
188
- defined?(@tag) ? @tag == :implicit : nil
188
+ defined?(@tag) ? @tag == :implicit : nil # rubocop:disable Style/ReturnNilInPredicateMethodDefinition
189
189
  end
190
190
 
191
191
  # @abstract This method SHOULD be partly implemented by subclasses, which
@@ -225,7 +225,7 @@ module RASN1
225
225
  # @return [Integer] total number of parsed bytes
226
226
  # @raise [ASN1Error] error on parsing
227
227
  def parse!(der, ber: false)
228
- total_length, data = do_parse(der, ber)
228
+ total_length, data = do_parse(der, ber: ber)
229
229
  return 0 if total_length.zero?
230
230
 
231
231
  if explicit?
@@ -300,6 +300,41 @@ module RASN1
300
300
  end
301
301
  end
302
302
 
303
+ # @private Parse tage and length from binary string. Return data length and binary data.
304
+ # @param [String] der
305
+ # @param [Boolean] ber
306
+ # @return [Array(::Integer, String)]
307
+ # @since 0.15.0 was private before
308
+ def do_parse(der, ber: false)
309
+ return [0, ''] unless check_id(der)
310
+
311
+ id_size = Types.decode_identifier_octets(der).last
312
+ total_length, data = get_data(der[id_size..], ber)
313
+ total_length += id_size
314
+ @no_value = false
315
+
316
+ [total_length, data]
317
+ end
318
+
319
+ # @private Delegate to #explicit type to generate sub-value
320
+ # @param [String] data
321
+ # @return [void]
322
+ # @since 0.15.0 was private before
323
+ def do_parse_explicit(data)
324
+ type = explicit_type
325
+ type.parse!(data)
326
+ @value = type.value
327
+ end
328
+
329
+ # Make value from DER/BER string
330
+ # @param [String] der
331
+ # @param [::Boolean] ber
332
+ # @return [void]
333
+ # @since 0.15.0 was private before
334
+ def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
335
+ @value = der
336
+ end
337
+
303
338
  private
304
339
 
305
340
  def trace_real
@@ -324,7 +359,7 @@ module RASN1
324
359
  lines << str
325
360
  end
326
361
  str[compute_trace_index(byte_count, 3), 2] = '%02x' % byte
327
- str[compute_trace_index(byte_count, 1, 49)] = byte >= 32 && byte <= 126 ? byte.chr : '.'
362
+ str[compute_trace_index(byte_count, 1, 49)] = byte.between?(32, 126) ? byte.chr : '.'
328
363
  byte_count += 1
329
364
  end
330
365
  lines.map(&:rstrip).join << "\n"
@@ -349,7 +384,7 @@ module RASN1
349
384
  end
350
385
 
351
386
  def msg_type(no_id: false)
352
- msg = name.nil? ? +'' : +"#{name} "
387
+ msg = name.nil? ? +'' : "#{name} "
353
388
  msg << "[ #{asn1_class_to_s}#{id} ] " unless no_id
354
389
  msg << if explicit?
355
390
  +'EXPLICIT '
@@ -391,24 +426,6 @@ module RASN1
391
426
  end
392
427
  end
393
428
 
394
- def do_parse(der, ber)
395
- return [0, ''] unless check_id(der)
396
-
397
- id_size = Types.decode_identifier_octets(der).last
398
- total_length, data = get_data(der[id_size..-1], ber)
399
- total_length += id_size
400
- @no_value = false
401
-
402
- [total_length, data]
403
- end
404
-
405
- def do_parse_explicit(data)
406
- # Delegate to #explicit type to generate sub-value
407
- type = explicit_type
408
- type.parse!(data)
409
- @value = type.value
410
- end
411
-
412
429
  def value_to_der
413
430
  case @value
414
431
  when Base
@@ -418,10 +435,6 @@ module RASN1
418
435
  end
419
436
  end
420
437
 
421
- def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
422
- @value = der
423
- end
424
-
425
438
  def set_class(asn1_class) # rubocop:disable Naming/AccessorMethodName
426
439
  case asn1_class
427
440
  when nil
@@ -533,7 +546,11 @@ module RASN1
533
546
  end
534
547
  end
535
548
 
536
- def check_id(der)
549
+ # Check ID from +der+ is the one expected
550
+ # @return [Boolean] +true+ is ID is expected, +false+ if it is not but +self+ is {#optional?}
551
+ # or has a {#default} value.
552
+ # @raise [ASN1Error] ID was not expected, is not optional and has no default value
553
+ def check_id(der) # rubocop:disable Naming/PredicateMethod
537
554
  expected_id = encode_identifier_octets
538
555
  real_id = der[0, expected_id.size]
539
556
  return true if real_id == expected_id
@@ -595,13 +612,13 @@ module RASN1
595
612
  end
596
613
 
597
614
  def raise_id_error(der)
598
- msg = name.nil? ? +'' : +"#{name}: "
615
+ msg = name.nil? ? +'' : "#{name}: "
599
616
  msg << "Expected #{self2name} but get #{der2name(der)}"
600
617
  raise ASN1Error, msg
601
618
  end
602
619
 
603
620
  def self2name
604
- name = +"#{asn1_class.to_s.upcase} #{constructed? ? 'CONSTRUCTED' : 'PRIMITIVE'}"
621
+ name = "#{asn1_class.to_s.upcase} #{constructed? ? 'CONSTRUCTED' : 'PRIMITIVE'}"
605
622
  if implicit? || explicit?
606
623
  name << ' 0x%X (0x%s)' % [id, bin2hex(encode_identifier_octets)]
607
624
  else
@@ -613,7 +630,7 @@ module RASN1
613
630
  return 'no ID' if der.nil? || der.empty?
614
631
 
615
632
  asn1_class, pc, id, id_size = Types.decode_identifier_octets(der)
616
- name = +"#{asn1_class.to_s.upcase} #{pc.to_s.upcase}"
633
+ name = "#{asn1_class.to_s.upcase} #{pc.to_s.upcase}"
617
634
  type = find_type(id)
618
635
  name << " #{type.nil? ? '0x%X (0x%s)' % [id, bin2hex(der[0...id_size])] : type.encoded_type}"
619
636
  end
@@ -48,6 +48,18 @@ module RASN1
48
48
  super || (!@default.nil? && (@bit_length != @default_bit_length))
49
49
  end
50
50
 
51
+ # Make value from DER/BER string. Also set {#bit_length}.
52
+ # @param [String] der
53
+ # @param [::Boolean] ber
54
+ # @return [void]
55
+ # @see Types::Base#der_to_value
56
+ def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
57
+ unused = der.unpack1('C').to_i
58
+ value = der[1..].to_s
59
+ @bit_length = value.length * 8 - unused
60
+ @value = value
61
+ end
62
+
51
63
  private
52
64
 
53
65
  # @author Sylvain Daubert
@@ -80,13 +92,6 @@ module RASN1
80
92
  value[0, max_len].to_s
81
93
  end
82
94
 
83
- def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
84
- unused = der.unpack1('C').to_i
85
- value = der[1..-1].to_s
86
- @bit_length = value.length * 8 - unused
87
- @value = value
88
- end
89
-
90
95
  def explicit_type
91
96
  self.class.new(name: name, value: @value, bit_length: @bit_length)
92
97
  end
@@ -8,23 +8,15 @@ module RASN1
8
8
  class BmpString < OctetString
9
9
  # BmpString id value
10
10
  ID = 30
11
+ # UniversalString encoding
12
+ # @since 0.15.0
13
+ ENCODING = Encoding::UTF_16BE
11
14
 
12
15
  # Get ASN.1 type
13
16
  # @return [String]
14
17
  def self.type
15
18
  'BmpString'
16
19
  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
20
  end
29
21
  end
30
22
  end
@@ -8,22 +8,23 @@ module RASN1
8
8
  # Boolean id value
9
9
  ID = 0x01
10
10
 
11
- # @private
11
+ # DER true value
12
12
  DER_TRUE = 0xff
13
- # @private
13
+ # DER false value
14
14
  DER_FALSE = 0
15
15
 
16
16
  # @return [false]
17
- def void_value
17
+ def void_value # rubocop:disable Naming/PredicateMethod
18
18
  false
19
19
  end
20
20
 
21
- private
22
-
23
- def value_to_der
24
- [@value ? DER_TRUE : DER_FALSE].pack('C')
25
- end
26
-
21
+ # Make boolean value from DER/BER string.
22
+ # @param [String] der
23
+ # @param [::Boolean] ber
24
+ # @return [void]
25
+ # @see Types::Base#der_to_value
26
+ # @raise [ASN1Error] +der+ is not 1-byte long
27
+ # @raise [ASN1Error] +der+ is not {DER_TRUE} nor {DER_FALSE} and +ber+ is +false+
27
28
  def der_to_value(der, ber: false)
28
29
  raise ASN1Error, "tag #{@name}: BOOLEAN should have a length of 1" unless der.size == 1
29
30
 
@@ -40,6 +41,12 @@ module RASN1
40
41
  end
41
42
  end
42
43
 
44
+ private
45
+
46
+ def value_to_der
47
+ [@value ? DER_TRUE : DER_FALSE].pack('C')
48
+ end
49
+
43
50
  def trace_data
44
51
  return super if explicit?
45
52
 
@@ -57,6 +57,8 @@ module RASN1
57
57
  @value[@chosen].value
58
58
  when Model
59
59
  @value[@chosen]
60
+ when Wrapper
61
+ @value[@chosen].element
60
62
  end
61
63
  end
62
64
 
@@ -75,10 +77,25 @@ module RASN1
75
77
  # @return [Integer] total number of parsed bytes
76
78
  # @raise [ASN1Error] error on parsing
77
79
  def parse!(der, ber: false)
80
+ len, data = do_parse(der, ber: ber)
81
+ return 0 if len.zero?
82
+
83
+ element = @value[@chosen]
84
+ if element.explicit?
85
+ element.do_parse_explicit(data)
86
+ else
87
+ element.der_to_value(data, ber: ber)
88
+ end
89
+ len
90
+ end
91
+
92
+ # @private
93
+ # @see Types::Base#do_parse
94
+ # @since 0.15.0 Specific +#do_parse+ to handle recursivity
95
+ def do_parse(der, ber: false)
78
96
  @value.each_with_index do |element, i|
79
97
  @chosen = i
80
- nb_bytes = element.parse!(der, ber: ber)
81
- return nb_bytes
98
+ return element.do_parse(der, ber: ber)
82
99
  rescue ASN1Error
83
100
  @chosen = nil
84
101
  next
@@ -88,7 +105,23 @@ module RASN1
88
105
  @value = void_value
89
106
  raise ASN1Error, "CHOICE #{@name}: no type matching #{der.inspect}" unless optional?
90
107
 
91
- 0
108
+ [0, ''.b]
109
+ end
110
+
111
+ # Make choice value from DER/BER string.
112
+ # @param [String] der
113
+ # @param [::Boolean] ber
114
+ # @return [void]
115
+ # @since 0.15.0 Specific +#der_to_value+ to handle recursivity
116
+ def der_to_value(der, ber: false)
117
+ @value.each_with_index do |element, i|
118
+ @chosen = i
119
+ element.parse!(der, ber: ber)
120
+ break
121
+ rescue ASN1Error
122
+ @chosen = nil
123
+ next
124
+ end
92
125
  end
93
126
 
94
127
  # @param [::Integer] level
@@ -108,6 +141,13 @@ module RASN1
108
141
  msg_type(no_id: true)
109
142
  end
110
143
 
144
+ # Return empty array
145
+ # @return [Array()]
146
+ # @since 0.15.0
147
+ def void_value
148
+ []
149
+ end
150
+
111
151
  private
112
152
 
113
153
  def check_chosen
@@ -37,8 +37,11 @@ module RASN1
37
37
  super
38
38
  end
39
39
 
40
- private
41
-
40
+ # Make value from +der+ string and check constraints
41
+ # @param [String] der
42
+ # @param [::Boolean] ber
43
+ # @return [void]
44
+ # @raise [ConstraintError] constraint is not verified
42
45
  def der_to_value(der, ber: false)
43
46
  super
44
47
  self.class.check_constraint(@value)
@@ -44,18 +44,10 @@ module RASN1
44
44
  Time.now
45
45
  end
46
46
 
47
- private
48
-
49
- def value_to_der
50
- utc_value = @value.getutc
51
- if utc_value.nsec.positive?
52
- der = utc_value.strftime('%Y%m%d%H%M%S.%9NZ')
53
- der.sub(/0+Z/, 'Z')
54
- else
55
- utc_value.strftime('%Y%m%d%H%M%SZ')
56
- end
57
- end
58
-
47
+ # Make time value from +der+ string
48
+ # @param [String] der
49
+ # @param [::Boolean] ber
50
+ # @return [void]
59
51
  def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
60
52
  date_hour, fraction = der.split('.')
61
53
  date_hour = date_hour.to_s
@@ -70,19 +62,20 @@ module RASN1
70
62
  end
71
63
  end
72
64
 
65
+ private
66
+
67
+ def value_to_der
68
+ utc_value = @value.getutc
69
+ if utc_value.nsec.positive?
70
+ der = utc_value.strftime('%Y%m%d%H%M%S.%9NZ')
71
+ der.sub(/0+Z/, 'Z')
72
+ else
73
+ utc_value.strftime('%Y%m%d%H%M%SZ')
74
+ end
75
+ end
76
+
73
77
  def value_when_fraction_empty(date_hour)
74
- # Ruby 3.0: special handle for timezone
75
- # From 3.1: "Z" and "-0100" are supported
76
- # Below 3.1: should be "-01:00" or "+00:00"
77
- tz = if date_hour[-1] == 'Z'
78
- date_hour.slice!(-1, 1)
79
- '+00:00' # Ruby 3.0: to remove after end-of support of ruby 3.0
80
- elsif date_hour.match?(/[+-]\d+$/)
81
- # Ruby 3.0
82
- # date_hour.slice!(-5, 5)
83
- zone = date_hour.slice!(-5, 5).to_s
84
- "#{zone[0, 3]}:#{zone[3, 2]}"
85
- end
78
+ tz = compute_tz(date_hour)
86
79
  year = date_hour.slice!(0, 4).to_i
87
80
  month = date_hour.slice!(0, 2).to_i
88
81
  day = date_hour.slice!(0, 2).to_i
@@ -92,6 +85,21 @@ module RASN1
92
85
  @value = Time.new(year, month, day, hour, minute, second, tz)
93
86
  end
94
87
 
88
+ # Ruby 3.0: special handle for timezone
89
+ # From 3.1: "Z" and "-0100" are supported
90
+ # Below 3.1: should be "-01:00" or "+00:00"
91
+ def compute_tz(date_hour)
92
+ if date_hour.end_with?('Z')
93
+ date_hour.slice!(-1, 1)
94
+ '+00:00' # Ruby 3.0: to remove after end-of support of ruby 3.0
95
+ elsif date_hour.match?(/[+-]\d+$/)
96
+ # Ruby 3.0
97
+ # date_hour.slice!(-5, 5)
98
+ zone = date_hour.slice!(-5, 5).to_s
99
+ "#{zone[0, 3]}:#{zone[3, 2]}"
100
+ end
101
+ end
102
+
95
103
  def value_when_fraction_ends_with_z(date_hour, fraction)
96
104
  fraction = fraction[0...-1]
97
105
  date_hour << 'Z'
@@ -7,23 +7,15 @@ module RASN1
7
7
  class IA5String < OctetString
8
8
  # IA5String id value
9
9
  ID = 22
10
+ # UniversalString encoding
11
+ # @since 0.15.0
12
+ ENCODING = Encoding::US_ASCII
10
13
 
11
14
  # Get ASN.1 type
12
15
  # @return [String]
13
16
  def self.type
14
17
  'IA5String'
15
18
  end
16
-
17
- private
18
-
19
- def value_to_der
20
- @value.to_s.dup.force_encoding('US-ASCII').b
21
- end
22
-
23
- def der_to_value(der, ber: false)
24
- super
25
- @value.to_s.dup.force_encoding('US-ASCII')
26
- end
27
19
  end
28
20
  end
29
21
  end
@@ -54,6 +54,19 @@ module RASN1
54
54
  end
55
55
  end
56
56
 
57
+ # Make integer value from +der+ string.
58
+ # @param [String] der
59
+ # @param [::Boolean] ber
60
+ # @return [void]
61
+ def der_to_value(der, ber: false)
62
+ int_value = der_to_int_value(der, ber: ber)
63
+ @value = if @enum.empty?
64
+ int_value
65
+ else
66
+ int_to_enum(int_value)
67
+ end
68
+ end
69
+
57
70
  private
58
71
 
59
72
  def initialize_enum(enum)
@@ -136,15 +149,6 @@ module RASN1
136
149
  @enum.key(int) || int
137
150
  end
138
151
 
139
- def der_to_value(der, ber: false)
140
- int_value = der_to_int_value(der, ber: ber)
141
- @value = if @enum.empty?
142
- int_value
143
- else
144
- int_to_enum(int_value)
145
- end
146
- end
147
-
148
152
  def explicit_type
149
153
  self.class.new(name: name, enum: enum)
150
154
  end
@@ -21,18 +21,23 @@ module RASN1
21
21
  !optional?
22
22
  end
23
23
 
24
- private
25
-
26
- def value_to_der
27
- ''
28
- end
29
-
24
+ # Check +der+ string
25
+ # @param [String] der
26
+ # @param [::Boolean] ber
27
+ # @return [void]
28
+ # @raise [ASN1Error] +der+ is not empty
30
29
  def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
31
30
  raise ASN1Error, 'NULL should not have content!' if der.length.positive?
32
31
 
33
32
  @no_value = true
34
33
  @value = void_value
35
34
  end
35
+
36
+ private
37
+
38
+ def value_to_der
39
+ ''
40
+ end
36
41
  end
37
42
  end
38
43
  end
@@ -7,6 +7,8 @@ module RASN1
7
7
  class NumericString < OctetString
8
8
  # NumericString id value
9
9
  ID = 18
10
+ # Invalid characters in NumericString
11
+ INVALID_CHARS = /([^0-9 ])/
10
12
 
11
13
  # Get ASN.1 type
12
14
  # @return [String]
@@ -14,6 +16,16 @@ module RASN1
14
16
  'NumericString'
15
17
  end
16
18
 
19
+ # Make string value from +der+ string
20
+ # @param [String] der
21
+ # @param [::Boolean] ber
22
+ # @return [void]
23
+ # @raise [ASN1Error] invalid characters detected
24
+ def der_to_value(der, ber: false)
25
+ super
26
+ check_characters
27
+ end
28
+
17
29
  private
18
30
 
19
31
  def value_to_der
@@ -21,13 +33,8 @@ module RASN1
21
33
  @value.to_s.b
22
34
  end
23
35
 
24
- def der_to_value(der, ber: false)
25
- super
26
- check_characters
27
- end
28
-
29
36
  def check_characters
30
- raise ASN1Error, "NUMERIC STRING #{@name}: invalid character: '#{$1}'" if @value.to_s =~ /([^0-9 ])/
37
+ raise ASN1Error, "NUMERIC STRING #{@name}: invalid character: '#{$1}'" if @value.to_s =~ INVALID_CHARS
31
38
  end
32
39
  end
33
40
  end
@@ -4,30 +4,15 @@ module RASN1
4
4
  module Types
5
5
  # ASN.1 Object ID
6
6
  # @author Sylvain Daubert
7
+ # @author LemonTree55
7
8
  class ObjectId < Primitive
8
9
  # ObjectId id value
9
10
  ID = 6
10
11
 
11
- private
12
-
13
- def value_to_der
14
- ids = @value.to_s.split('.').map(&:to_i)
15
-
16
- raise ASN1Error, "OBJECT ID #{@name}: first subidentifier should be less than 3" if ids[0] > 2
17
- raise ASN1Error, "OBJECT ID #{@name}: second subidentifier should be less than 40" if (ids[0] < 2) && (ids[1] > 39)
18
-
19
- ids[0, 2] = ids[0] * 40 + ids[1]
20
- octets = []
21
- ids.each do |v|
22
- if v < 128
23
- octets << v
24
- else
25
- octets.concat(unsigned_to_chained_octets(v))
26
- end
27
- end
28
- octets.pack('C*')
29
- end
30
-
12
+ # Make object id value from +der+ string
13
+ # @param [String] der
14
+ # @param [::Boolean] ber
15
+ # @return [void]
31
16
  def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
32
17
  bytes = der.unpack('C*')
33
18
 
@@ -35,7 +20,7 @@ module RASN1
35
20
  current_id = 0
36
21
  bytes.each do |byte|
37
22
  current_id = (current_id << 7) | (byte & 0x7f)
38
- if (byte & 0x80).zero?
23
+ if byte.nobits?(0x80)
39
24
  ids << current_id
40
25
  current_id = 0
41
26
  end
@@ -47,6 +32,33 @@ module RASN1
47
32
 
48
33
  @value = ids.join('.')
49
34
  end
35
+
36
+ private
37
+
38
+ # @raise [ASN1Error]
39
+ def value_to_der
40
+ ids = @value.to_s.split('.').map(&:to_i)
41
+
42
+ check_first_ids(ids)
43
+
44
+ ids[0, 2] = ids[0] * 40 + ids[1]
45
+ octets = []
46
+ ids.each do |v|
47
+ if v < 128
48
+ octets << v
49
+ else
50
+ octets.concat(unsigned_to_chained_octets(v))
51
+ end
52
+ end
53
+ octets.pack('C*')
54
+ end
55
+
56
+ # @param [Array[::Integer]] ids
57
+ # @raise [ASN1Error]
58
+ def check_first_ids(ids)
59
+ raise ASN1Error, "OBJECT ID #{@name}: first subidentifier should be less than 3" if ids[0] > 2
60
+ raise ASN1Error, "OBJECT ID #{@name}: second subidentifier should be less than 40" if (ids[0] < 2) && (ids[1] > 39)
61
+ end
50
62
  end
51
63
  end
52
64
  end
@@ -21,6 +21,32 @@ module RASN1
21
21
  str = common_inspect(level)
22
22
  str << " #{value.inspect}"
23
23
  end
24
+
25
+ # Make string value from +der+ string. Force encoding to UTF-8
26
+ # @param [String] der
27
+ # @param [::Boolean] ber
28
+ # @return [void]
29
+ # @since 0.15.0 Handle ENCODING constant, if defined by subclass
30
+ def der_to_value(der, ber: false)
31
+ klass = self.class
32
+ if klass.const_defined?(:ENCODING)
33
+ @value = der.to_s.dup.force_encoding(klass.const_get(:ENCODING))
34
+ else
35
+ super
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ # @since 0.15.0 Handle ENCODING constant, if defined by subclass
42
+ def value_to_der
43
+ klass = self.class
44
+ if klass.const_defined?(:ENCODING)
45
+ @value.to_s.encode(klass.const_get(:ENCODING)).b
46
+ else
47
+ super
48
+ end
49
+ end
24
50
  end
25
51
  end
26
52
  end