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.
- checksums.yaml +4 -4
- data/README.md +13 -6
- data/lib/rasn1/model.rb +186 -146
- data/lib/rasn1/tracer.rb +4 -4
- data/lib/rasn1/types/any.rb +5 -3
- data/lib/rasn1/types/base.rb +49 -32
- data/lib/rasn1/types/bit_string.rb +12 -7
- data/lib/rasn1/types/bmp_string.rb +3 -11
- data/lib/rasn1/types/boolean.rb +16 -9
- data/lib/rasn1/types/choice.rb +43 -3
- data/lib/rasn1/types/constrained.rb +5 -2
- data/lib/rasn1/types/generalized_time.rb +32 -24
- data/lib/rasn1/types/ia5string.rb +3 -11
- data/lib/rasn1/types/integer.rb +13 -9
- data/lib/rasn1/types/null.rb +11 -6
- data/lib/rasn1/types/numeric_string.rb +13 -6
- data/lib/rasn1/types/object_id.rb +33 -21
- data/lib/rasn1/types/octet_string.rb +26 -0
- data/lib/rasn1/types/printable_string.rb +13 -6
- data/lib/rasn1/types/sequence.rb +16 -12
- data/lib/rasn1/types/sequence_of.rb +15 -11
- data/lib/rasn1/types/universal_string.rb +3 -11
- data/lib/rasn1/types/utc_time.rb +17 -7
- data/lib/rasn1/types/utf8_string.rb +3 -11
- data/lib/rasn1/types/visible_string.rb +14 -2
- data/lib/rasn1/types.rb +6 -5
- data/lib/rasn1/version.rb +2 -1
- data/lib/rasn1/wrapper.rb +72 -18
- data/lib/rasn1.rb +5 -2
- metadata +2 -2
data/lib/rasn1/types/base.rb
CHANGED
@@ -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
|
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? ? +'' :
|
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
|
-
|
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? ? +'' :
|
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 =
|
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 =
|
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
|
data/lib/rasn1/types/boolean.rb
CHANGED
@@ -8,22 +8,23 @@ module RASN1
|
|
8
8
|
# Boolean id value
|
9
9
|
ID = 0x01
|
10
10
|
|
11
|
-
#
|
11
|
+
# DER true value
|
12
12
|
DER_TRUE = 0xff
|
13
|
-
#
|
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
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
|
data/lib/rasn1/types/choice.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
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
|
data/lib/rasn1/types/integer.rb
CHANGED
@@ -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
|
data/lib/rasn1/types/null.rb
CHANGED
@@ -21,18 +21,23 @@ module RASN1
|
|
21
21
|
!optional?
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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 =~
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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 (
|
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
|