rasn1 0.16.2 → 0.17.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 +25 -10
- data/lib/rasn1/errors.rb +2 -2
- data/lib/rasn1/model/accel.rb +229 -0
- data/lib/rasn1/model.rb +125 -211
- data/lib/rasn1/tracer.rb +34 -14
- data/lib/rasn1/types/any.rb +24 -3
- data/lib/rasn1/types/base.rb +132 -36
- data/lib/rasn1/types/bit_string.rb +18 -5
- data/lib/rasn1/types/boolean.rb +14 -3
- data/lib/rasn1/types/choice.rb +39 -23
- data/lib/rasn1/types/constrained.rb +4 -3
- data/lib/rasn1/types/constructed.rb +4 -2
- data/lib/rasn1/types/enumerated.rb +9 -8
- data/lib/rasn1/types/generalized_time.rb +32 -13
- data/lib/rasn1/types/integer.rb +67 -11
- data/lib/rasn1/types/null.rb +7 -3
- data/lib/rasn1/types/numeric_string.rb +14 -2
- data/lib/rasn1/types/object_id.rb +15 -4
- data/lib/rasn1/types/octet_string.rb +3 -3
- data/lib/rasn1/types/primitive.rb +4 -0
- data/lib/rasn1/types/printable_string.rb +9 -2
- data/lib/rasn1/types/sequence.rb +7 -3
- data/lib/rasn1/types/sequence_of.rb +28 -8
- data/lib/rasn1/types/set_of.rb +1 -1
- data/lib/rasn1/types/utc_time.rb +7 -2
- data/lib/rasn1/types.rb +5 -5
- data/lib/rasn1/version.rb +1 -1
- data/lib/rasn1/wrapper.rb +38 -7
- data/lib/rasn1.rb +8 -7
- metadata +5 -4
data/lib/rasn1/types/choice.rb
CHANGED
|
@@ -10,32 +10,44 @@ module RASN1
|
|
|
10
10
|
module Types
|
|
11
11
|
# A ASN.1 CHOICE is a choice between different types.
|
|
12
12
|
#
|
|
13
|
-
#
|
|
14
|
-
# A CHOICE is defined this way:
|
|
13
|
+
# @example Create a CHOICE
|
|
15
14
|
# choice = Choice.new
|
|
16
15
|
# choice.value = [Integer.new(implicit: 0, class: :context),
|
|
17
16
|
# Integer.new(implicit: 1, class: :context),
|
|
18
17
|
# OctetString.new(implicit: 2, class: :context)]
|
|
19
|
-
#
|
|
20
|
-
# choice.chosen = 0 # choose
|
|
21
|
-
#
|
|
18
|
+
# # Choose an element
|
|
19
|
+
# choice.chosen = 0 # choose int1
|
|
20
|
+
# # Set chosen value
|
|
22
21
|
# choise.value[choice.chosen].value = 1
|
|
23
|
-
#
|
|
24
|
-
#
|
|
22
|
+
# # Also set chosen value
|
|
23
|
+
# choise.set_chosen_value(1)
|
|
24
|
+
# # Got chosen value
|
|
25
25
|
# choise.value[choice.chosen].value # => 1
|
|
26
26
|
# choice.chosen_value # => 1
|
|
27
27
|
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
28
|
+
# @example Encode a CHOICE
|
|
29
|
+
# choice = Choice.new
|
|
30
|
+
# choice.value = [Integer.new(implicit: 0, class: :context, value: 1),
|
|
31
|
+
# Integer.new(implicit: 1, class: :context),
|
|
32
|
+
# OctetString.new(implicit: 2, class: :context, value: "a")]
|
|
33
|
+
# # to_der only encodes the chosen value
|
|
34
|
+
# choice.chosen = 0 # choose int1
|
|
35
|
+
# choice.to_der # => "\x80\x01\x01"
|
|
36
|
+
# # another choice, another encoding string
|
|
37
|
+
# choice.chosen_value = 2
|
|
38
|
+
# choice.to_der # => "\x82\x01a"
|
|
31
39
|
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
40
|
+
# @example Parse a CHOICE
|
|
41
|
+
# choice = Choice.new
|
|
42
|
+
# choice.value = [Integer.new(implicit: 0, class: :context, value: 1),
|
|
43
|
+
# Integer.new(implicit: 1, class: :context),
|
|
44
|
+
# OctetString.new(implicit: 2, class: :context, value: "a")]
|
|
45
|
+
# # Parse an octet string
|
|
46
|
+
# choice.parse!("\x82\x03abc")
|
|
37
47
|
# choice.chosen # => 2
|
|
38
48
|
# choice.chosen_value # => "abc"
|
|
49
|
+
# # Parse an unexpected value
|
|
50
|
+
# choice.parse!("\x04\x03abc") # => RASN1::ASN1Error
|
|
39
51
|
# @author Sylvain Daubert
|
|
40
52
|
class Choice < Base
|
|
41
53
|
# Chosen type
|
|
@@ -44,7 +56,7 @@ module RASN1
|
|
|
44
56
|
|
|
45
57
|
# Set chosen value.
|
|
46
58
|
# @note {#chosen} MUST be set before calling this method
|
|
47
|
-
# @param [Object]
|
|
59
|
+
# @param value [Object]
|
|
48
60
|
# @return [Object] value
|
|
49
61
|
# @raise [ChoiceError] {#chosen} not set
|
|
50
62
|
def set_chosen_value(value) # rubocop:disable Naming/AccessorMethodName
|
|
@@ -68,9 +80,10 @@ module RASN1
|
|
|
68
80
|
end
|
|
69
81
|
end
|
|
70
82
|
|
|
71
|
-
#
|
|
83
|
+
# Encode Choice into DER encoding
|
|
72
84
|
# @return [String] DER-formated string
|
|
73
85
|
# @raise [ChoiceError] {#chosen} not set
|
|
86
|
+
# @note {#chosen} MUST be set before calling this method
|
|
74
87
|
def to_der
|
|
75
88
|
check_chosen
|
|
76
89
|
@value[@chosen].to_der
|
|
@@ -78,8 +91,8 @@ module RASN1
|
|
|
78
91
|
|
|
79
92
|
# Parse a DER string. This method updates object by setting {#chosen} and
|
|
80
93
|
# chosen value.
|
|
81
|
-
# @param [String]
|
|
82
|
-
# @param [Boolean]
|
|
94
|
+
# @param der [String] DER string
|
|
95
|
+
# @param ber [Boolean] if +true+, accept BER encoding
|
|
83
96
|
# @return [Integer] total number of parsed bytes
|
|
84
97
|
# @raise [ASN1Error] error on parsing
|
|
85
98
|
def parse!(der, ber: false)
|
|
@@ -96,6 +109,7 @@ module RASN1
|
|
|
96
109
|
end
|
|
97
110
|
|
|
98
111
|
# @private
|
|
112
|
+
# @!macro do_parse
|
|
99
113
|
# @see Types::Base#do_parse
|
|
100
114
|
# @since 0.15.0 Specific +#do_parse+ to handle recursivity
|
|
101
115
|
def do_parse(der, ber: false)
|
|
@@ -115,8 +129,8 @@ module RASN1
|
|
|
115
129
|
end
|
|
116
130
|
|
|
117
131
|
# Make choice value from DER/BER string.
|
|
118
|
-
# @param [String]
|
|
119
|
-
# @param [::Boolean]
|
|
132
|
+
# @param der [String]
|
|
133
|
+
# @param ber [::Boolean]
|
|
120
134
|
# @return [void]
|
|
121
135
|
# @since 0.15.0 Specific +#der_to_value+ to handle recursivity
|
|
122
136
|
def der_to_value(der, ber: false)
|
|
@@ -130,7 +144,7 @@ module RASN1
|
|
|
130
144
|
end
|
|
131
145
|
end
|
|
132
146
|
|
|
133
|
-
# @param [::Integer]
|
|
147
|
+
# @param level [::Integer]
|
|
134
148
|
# @return [String]
|
|
135
149
|
def inspect(level=0)
|
|
136
150
|
str = common_inspect(level)
|
|
@@ -148,7 +162,7 @@ module RASN1
|
|
|
148
162
|
end
|
|
149
163
|
|
|
150
164
|
# Return empty array
|
|
151
|
-
# @return [Array
|
|
165
|
+
# @return [Array]
|
|
152
166
|
# @since 0.15.0
|
|
153
167
|
def void_value
|
|
154
168
|
[]
|
|
@@ -156,6 +170,8 @@ module RASN1
|
|
|
156
170
|
|
|
157
171
|
private
|
|
158
172
|
|
|
173
|
+
# @return [void]
|
|
174
|
+
# @raise [ChoiceError] {#chosen} is not set
|
|
159
175
|
def check_chosen
|
|
160
176
|
raise ChoiceError.new(self) if !defined?(@chosen) || @chosen.nil?
|
|
161
177
|
end
|
|
@@ -25,7 +25,7 @@ module RASN1
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
# Check constraint, if defined
|
|
28
|
-
# @param [Object]
|
|
28
|
+
# @param value [Object] the value of the type to check
|
|
29
29
|
# @raise [ConstraintError] constraint is not verified
|
|
30
30
|
def check_constraint(value)
|
|
31
31
|
return unless constrained?
|
|
@@ -36,6 +36,7 @@ module RASN1
|
|
|
36
36
|
extend ClassMethods
|
|
37
37
|
|
|
38
38
|
# Redefined +#value=+ to check constraint before assigning +val+
|
|
39
|
+
# @!macro value_setter
|
|
39
40
|
# @see Types::Base#value=
|
|
40
41
|
# @raise [ConstraintError] constraint is not verified
|
|
41
42
|
def value=(val)
|
|
@@ -44,8 +45,8 @@ module RASN1
|
|
|
44
45
|
end
|
|
45
46
|
|
|
46
47
|
# Make value from +der+ string and check constraints
|
|
47
|
-
# @param [String]
|
|
48
|
-
# @param [::Boolean]
|
|
48
|
+
# @param der [String]
|
|
49
|
+
# @param ber [::Boolean]
|
|
49
50
|
# @return [void]
|
|
50
51
|
# @raise [ConstraintError] constraint is not verified
|
|
51
52
|
def der_to_value(der, ber: false)
|
|
@@ -10,7 +10,9 @@ module RASN1
|
|
|
10
10
|
module Types
|
|
11
11
|
# @abstract This class SHOULD be used as base class for all ASN.1 primitive
|
|
12
12
|
# types.
|
|
13
|
-
#
|
|
13
|
+
# This is the base class for all ASN.1 constructed types. A constructed type combines similar or different
|
|
14
|
+
# {Primitive primitive} types into ordered or unordered groups
|
|
15
|
+
#
|
|
14
16
|
# @author Sylvain Daubert
|
|
15
17
|
class Constructed < Base
|
|
16
18
|
# Constructed value
|
|
@@ -30,7 +32,7 @@ module RASN1
|
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
34
|
|
|
33
|
-
# @param [::Integer]
|
|
35
|
+
# @param level [::Integer] (default: 0)
|
|
34
36
|
# @return [String]
|
|
35
37
|
def inspect(level=0)
|
|
36
38
|
case @value
|
|
@@ -10,18 +10,19 @@ module RASN1
|
|
|
10
10
|
module Types
|
|
11
11
|
# ASN.1 Enumerated
|
|
12
12
|
#
|
|
13
|
-
# An
|
|
14
|
-
# different
|
|
13
|
+
# An ENUMERATED type permits to assign names to integer values. {Integer} may
|
|
14
|
+
# also be enumerated, but the tag {ID} is different.
|
|
15
|
+
#
|
|
16
|
+
# @example Example 1
|
|
15
17
|
# enum = RASN1::Types::Enumerated.new(enum: { 'a' => 0, 'b' => 1, 'c' => 2 })
|
|
18
|
+
# enum.value = 'a'
|
|
19
|
+
# enum.value # => 'a'
|
|
20
|
+
# @example Example 2
|
|
16
21
|
# enum = RASN1::Types::Enumerated.new(enum: { a: 0, b: 1, c: 2 })
|
|
17
|
-
# Its value should be setting as an Integer or a String/symbol:
|
|
18
22
|
# enum.value = :b
|
|
19
23
|
# enum.value = 1 # equivalent to :b
|
|
20
|
-
#
|
|
21
|
-
# enum.value
|
|
22
|
-
# enum.value # => :b
|
|
23
|
-
# enum.value = 0
|
|
24
|
-
# enum.value # => :a
|
|
24
|
+
# # enum returned value is always symbolic (even if set with an integer)
|
|
25
|
+
# enum.value # => :b
|
|
25
26
|
# A {EnumeratedError} is raised when set value is not in enumeration.
|
|
26
27
|
# @author Sylvain Daubert
|
|
27
28
|
class Enumerated < Integer
|
|
@@ -15,26 +15,29 @@ module RASN1
|
|
|
15
15
|
# +{#value} of a {GeneralizedTime} should be a ruby Time.
|
|
16
16
|
#
|
|
17
17
|
# ===Notes
|
|
18
|
-
#
|
|
18
|
+
# On encoding, resulting string is always a UTC time, appended with +Z+.
|
|
19
19
|
# Minutes and seconds are always generated. Fractions of second are generated
|
|
20
20
|
# if value Time object have them.
|
|
21
21
|
#
|
|
22
|
-
# On parsing,
|
|
22
|
+
# On parsing, this class supports:
|
|
23
23
|
# * UTC times (ending with +Z+),
|
|
24
24
|
# * local times (no suffix),
|
|
25
25
|
# * local times with difference between UTC and this local time (ending with
|
|
26
26
|
# +sHHMM+, where +s+ is +++ or +-+, and +HHMM+ is the time differential
|
|
27
27
|
# betwen UTC and local time).
|
|
28
28
|
# These times may include minutes and seconds. Fractions of hour, minute and
|
|
29
|
-
# second are supported.
|
|
29
|
+
# second are also supported.
|
|
30
30
|
# @author Sylvain Daubert
|
|
31
|
+
# @author LemonTree55
|
|
31
32
|
class GeneralizedTime < Primitive
|
|
32
33
|
# GeneralizedTime id value
|
|
33
34
|
ID = 24
|
|
34
35
|
|
|
35
36
|
# @private
|
|
37
|
+
# Second count in one hour
|
|
36
38
|
HOUR_TO_SEC = 3600
|
|
37
39
|
# @private
|
|
40
|
+
# Second count in one minute
|
|
38
41
|
MINUTE_TO_SEC = 60
|
|
39
42
|
# @private
|
|
40
43
|
SECOND_TO_SEC = 1
|
|
@@ -51,8 +54,8 @@ module RASN1
|
|
|
51
54
|
end
|
|
52
55
|
|
|
53
56
|
# Make time value from +der+ string
|
|
54
|
-
# @param [String]
|
|
55
|
-
# @param [::Boolean]
|
|
57
|
+
# @param der [String]
|
|
58
|
+
# @param ber [::Boolean]
|
|
56
59
|
# @return [void]
|
|
57
60
|
def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
|
|
58
61
|
date_hour, fraction = der.split('.')
|
|
@@ -70,6 +73,7 @@ module RASN1
|
|
|
70
73
|
|
|
71
74
|
private
|
|
72
75
|
|
|
76
|
+
# @return [String]
|
|
73
77
|
def value_to_der
|
|
74
78
|
utc_value = @value.getutc
|
|
75
79
|
if utc_value.nsec.positive?
|
|
@@ -80,6 +84,9 @@ module RASN1
|
|
|
80
84
|
end
|
|
81
85
|
end
|
|
82
86
|
|
|
87
|
+
# Set internal value to a Time defined from date and hour from +date_hour+, without fraction.
|
|
88
|
+
# @param date_hour [String]
|
|
89
|
+
# @return [void]
|
|
83
90
|
def value_when_fraction_empty(date_hour)
|
|
84
91
|
tz = compute_tz(date_hour)
|
|
85
92
|
year = date_hour.slice!(0, 4).to_i
|
|
@@ -91,21 +98,21 @@ module RASN1
|
|
|
91
98
|
@value = Time.new(year, month, day, hour, minute, second, tz)
|
|
92
99
|
end
|
|
93
100
|
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
#
|
|
101
|
+
# Compute TZ from +date_hour+ string
|
|
102
|
+
# @param date_hour [String]
|
|
103
|
+
# @return [String]
|
|
97
104
|
def compute_tz(date_hour)
|
|
98
105
|
if date_hour.end_with?('Z')
|
|
99
106
|
date_hour.slice!(-1, 1)
|
|
100
|
-
'+00:00' # Ruby 3.0: to remove after end-of support of ruby 3.0
|
|
101
107
|
elsif date_hour.match?(/[+-]\d+$/)
|
|
102
|
-
|
|
103
|
-
# date_hour.slice!(-5, 5)
|
|
104
|
-
zone = date_hour.slice!(-5, 5).to_s
|
|
105
|
-
"#{zone[0, 3]}:#{zone[3, 2]}"
|
|
108
|
+
date_hour.slice!(-5, 5)
|
|
106
109
|
end
|
|
107
110
|
end
|
|
108
111
|
|
|
112
|
+
# Set value in special case where fraction ends with 'Z'
|
|
113
|
+
# @param date_hour [String]
|
|
114
|
+
# @param fraction [String]
|
|
115
|
+
# @return [void]
|
|
109
116
|
def value_when_fraction_ends_with_z(date_hour, fraction)
|
|
110
117
|
fraction = fraction[0...-1]
|
|
111
118
|
date_hour << 'Z'
|
|
@@ -114,6 +121,10 @@ module RASN1
|
|
|
114
121
|
fix_value(fraction, frac_base)
|
|
115
122
|
end
|
|
116
123
|
|
|
124
|
+
# Set value in general case
|
|
125
|
+
# @param date_hour [String]
|
|
126
|
+
# @param fraction [String]
|
|
127
|
+
# @return [void]
|
|
117
128
|
def value_on_others_cases(date_hour, fraction)
|
|
118
129
|
match = fraction.match(/(\d+)([+-]\d+)/)
|
|
119
130
|
if match
|
|
@@ -127,11 +138,18 @@ module RASN1
|
|
|
127
138
|
fix_value(fraction, frac_base)
|
|
128
139
|
end
|
|
129
140
|
|
|
141
|
+
# Fix internal value with +fraction+, based on +frac_base+
|
|
142
|
+
# @param fraction [String]
|
|
143
|
+
# @param frac_base [::Integer]
|
|
144
|
+
# @return [void]
|
|
130
145
|
def fix_value(fraction, frac_base)
|
|
131
146
|
frac = ".#{fraction}".to_r * frac_base
|
|
132
147
|
@value = (@value + frac) unless fraction.nil?
|
|
133
148
|
end
|
|
134
149
|
|
|
150
|
+
# Compute fraction base from +date_hour+ string
|
|
151
|
+
# @param date_hour [String]
|
|
152
|
+
# @return [::Integer]
|
|
135
153
|
def compute_frac_base(date_hour)
|
|
136
154
|
case date_hour.size
|
|
137
155
|
when 10, 11
|
|
@@ -152,6 +170,7 @@ module RASN1
|
|
|
152
170
|
end
|
|
153
171
|
end
|
|
154
172
|
|
|
173
|
+
# @return [String]
|
|
155
174
|
def trace_data
|
|
156
175
|
return super if explicit?
|
|
157
176
|
|
data/lib/rasn1/types/integer.rb
CHANGED
|
@@ -9,25 +9,50 @@
|
|
|
9
9
|
module RASN1
|
|
10
10
|
module Types
|
|
11
11
|
# ASN.1 Integer
|
|
12
|
+
#
|
|
13
|
+
# An INTEGER is a primitive type to represent integers.
|
|
14
|
+
# There is no limit on integer size.
|
|
15
|
+
#
|
|
16
|
+
# @example Simple Integers
|
|
17
|
+
# # Simple integer with a value associated
|
|
18
|
+
# int1 = RASN1::Types::Integer.new(value: 42)
|
|
19
|
+
# # Integer without value, but a default one
|
|
20
|
+
# int2 = RASN1::Types::Integer.new(default: -42)
|
|
21
|
+
#
|
|
22
|
+
# @example Enumerated Integer
|
|
23
|
+
# enum = RASN1::Types::Integer.new(enum: {one: 1, two: 2})
|
|
24
|
+
# enum.value = :two
|
|
25
|
+
# enum.value #=> :two
|
|
26
|
+
# enum.to_i #=> 2
|
|
12
27
|
# @author Sylvain Daubert
|
|
28
|
+
# @author LemonTree55
|
|
13
29
|
class Integer < Primitive
|
|
14
|
-
#
|
|
30
|
+
# Associated enumeration
|
|
31
|
+
# @return [Hash{String=>::Integer},nil]
|
|
15
32
|
attr_reader :enum
|
|
16
33
|
|
|
17
34
|
# Integer id value
|
|
18
35
|
ID = 2
|
|
19
36
|
|
|
20
|
-
#
|
|
37
|
+
# @!macro type_initialize
|
|
38
|
+
# @option options [Hash{String=>::Integer}] :enum enumeration hash. Keys are names, and values
|
|
21
39
|
# are integers.
|
|
22
40
|
# @raise [EnumeratedError] +:default+ value is unknown when +:enum+ key is present
|
|
23
|
-
# @see Base#initialize common options to all ASN.1 types
|
|
24
41
|
def initialize(options={})
|
|
25
42
|
super
|
|
26
43
|
initialize_enum(@options[:enum])
|
|
27
44
|
end
|
|
28
45
|
|
|
29
|
-
#
|
|
46
|
+
# Set integer value from a Ruby integer, or a String or a Symbol (only when {#enum} is defined).
|
|
47
|
+
# @param val [::Integer,String,Symbol,nil]
|
|
30
48
|
# @return [void]
|
|
49
|
+
# @note
|
|
50
|
+
# An enumerated INTEGER may be set with an integer value out of enumeration,
|
|
51
|
+
# only when no value is set.
|
|
52
|
+
# @raise [EnumeratedError] string/symbol value: no enum defined or +val+ not in enum
|
|
53
|
+
# @raise [EnumeratedError] integer value: value already set and new value not in enum
|
|
54
|
+
# @raise [TypeError] unsupported +val+ type
|
|
55
|
+
# @since 0.16.2 raise TypeError (was EnumeratedError)
|
|
31
56
|
def value=(val)
|
|
32
57
|
@no_value = false
|
|
33
58
|
case val
|
|
@@ -39,17 +64,17 @@ module RASN1
|
|
|
39
64
|
@no_value = true
|
|
40
65
|
@value = void_value
|
|
41
66
|
else
|
|
42
|
-
raise
|
|
67
|
+
raise TypeError, "#{val.class} not supported"
|
|
43
68
|
end
|
|
44
69
|
end
|
|
45
70
|
|
|
46
|
-
# @return [Integer]
|
|
71
|
+
# @return [::Integer]
|
|
47
72
|
def void_value
|
|
48
73
|
0
|
|
49
74
|
end
|
|
50
75
|
|
|
51
76
|
# Integer value
|
|
52
|
-
# @return [Integer]
|
|
77
|
+
# @return [::Integer]
|
|
53
78
|
def to_i
|
|
54
79
|
val = value? ? @value : @default
|
|
55
80
|
case val
|
|
@@ -61,8 +86,8 @@ module RASN1
|
|
|
61
86
|
end
|
|
62
87
|
|
|
63
88
|
# Make integer value from +der+ string.
|
|
64
|
-
# @param [String]
|
|
65
|
-
# @param [::Boolean]
|
|
89
|
+
# @param der [String]
|
|
90
|
+
# @param ber [::Boolean]
|
|
66
91
|
# @return [void]
|
|
67
92
|
def der_to_value(der, ber: false)
|
|
68
93
|
int_value = der_to_int_value(der, ber: ber)
|
|
@@ -75,6 +100,9 @@ module RASN1
|
|
|
75
100
|
|
|
76
101
|
private
|
|
77
102
|
|
|
103
|
+
# Initialize integer with given enum hash.
|
|
104
|
+
# @param enum [Hash{String=>::Integer}]
|
|
105
|
+
# @return [void]
|
|
78
106
|
def initialize_enum(enum)
|
|
79
107
|
@enum = enum || {}
|
|
80
108
|
return if @enum.empty?
|
|
@@ -85,6 +113,10 @@ module RASN1
|
|
|
85
113
|
check_enum_default
|
|
86
114
|
end
|
|
87
115
|
|
|
116
|
+
# Check defined default is coherent with enum
|
|
117
|
+
# @return [void]
|
|
118
|
+
# @raise [EnumeratedError] default value not defined in {#enum}
|
|
119
|
+
# @raise [TypeError] unsupported type for default value
|
|
88
120
|
def check_enum_default
|
|
89
121
|
case @default
|
|
90
122
|
when String, Symbol
|
|
@@ -99,6 +131,10 @@ module RASN1
|
|
|
99
131
|
end
|
|
100
132
|
end
|
|
101
133
|
|
|
134
|
+
# Set value from given string or symbol value
|
|
135
|
+
# @param val [String,Symbol]
|
|
136
|
+
# @return [void]
|
|
137
|
+
# @raise [EnumeratedError] no enum defined or +val+ not in enum
|
|
102
138
|
def value_from_string_or_symbol(val)
|
|
103
139
|
raise EnumeratedError, "#{@name} has no :enum" if @enum.empty?
|
|
104
140
|
raise EnumeratedError, "#{@name}: unknwon enumerated value #{val}" unless @enum.key? val
|
|
@@ -106,6 +142,10 @@ module RASN1
|
|
|
106
142
|
@value = val
|
|
107
143
|
end
|
|
108
144
|
|
|
145
|
+
# Set value from given integer value.
|
|
146
|
+
# @param val [::Integer]
|
|
147
|
+
# @return [void]
|
|
148
|
+
# @raise [EnumeratedError] +val+ not in enum
|
|
109
149
|
def value_from_integer(val)
|
|
110
150
|
if @enum.empty?
|
|
111
151
|
@value = val
|
|
@@ -116,6 +156,8 @@ module RASN1
|
|
|
116
156
|
end
|
|
117
157
|
end
|
|
118
158
|
|
|
159
|
+
# @param value [::Integer]
|
|
160
|
+
# @return [String]
|
|
119
161
|
def int_value_to_der(value)
|
|
120
162
|
size = compute_size(value)
|
|
121
163
|
comp_value = value >= 0 ? value : (~(-value) + 1) & ((1 << (size * 8)) - 1)
|
|
@@ -125,12 +167,16 @@ module RASN1
|
|
|
125
167
|
ary.reverse.pack('C*')
|
|
126
168
|
end
|
|
127
169
|
|
|
170
|
+
# Get size in bytes of +value+ integer
|
|
171
|
+
# @param value [::Integer]
|
|
172
|
+
# @return [::Integer]
|
|
128
173
|
def compute_size(value)
|
|
129
174
|
size = value.bit_length / 8 + ((value.bit_length % 8).positive? ? 1 : 0)
|
|
130
175
|
size = 1 if size.zero?
|
|
131
176
|
size
|
|
132
177
|
end
|
|
133
178
|
|
|
179
|
+
# @return [String]
|
|
134
180
|
def value_to_der
|
|
135
181
|
case @value
|
|
136
182
|
when String, Symbol
|
|
@@ -142,6 +188,9 @@ module RASN1
|
|
|
142
188
|
end
|
|
143
189
|
end
|
|
144
190
|
|
|
191
|
+
# @param der [String]
|
|
192
|
+
# @param ber [::Boolean]
|
|
193
|
+
# @return [::Integer]
|
|
145
194
|
def der_to_int_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
|
|
146
195
|
ary = der.unpack('C*')
|
|
147
196
|
v = ary.reduce(0) { |len, b| (len << 8) | b }
|
|
@@ -149,22 +198,29 @@ module RASN1
|
|
|
149
198
|
v
|
|
150
199
|
end
|
|
151
200
|
|
|
201
|
+
# Return value to show (enumerated if enum is defined, else integer)
|
|
202
|
+
# @param int [::Integer]
|
|
203
|
+
# @param check_enum [::Boolean]
|
|
204
|
+
# @return [String,::Integer]
|
|
205
|
+
# @raise [EnumeratedError] +check_enum+ is +true+, enum is defined, and +int+ is not in enum
|
|
152
206
|
def int_to_enum(int, check_enum: true)
|
|
153
207
|
raise EnumeratedError, "#{@name}: value #{int} not in enumeration" if check_enum && !@enum.value?(int)
|
|
154
208
|
|
|
155
209
|
@enum.key(int) || int
|
|
156
210
|
end
|
|
157
211
|
|
|
212
|
+
# @return [::Integer]
|
|
158
213
|
def explicit_type
|
|
159
214
|
self.class.new(name: name, enum: enum)
|
|
160
215
|
end
|
|
161
216
|
|
|
217
|
+
# @return [String]
|
|
162
218
|
def trace_data
|
|
163
219
|
return super if explicit?
|
|
164
|
-
return " #{der_to_int_value(raw_data)} (0x#{raw_data
|
|
220
|
+
return " #{der_to_int_value(raw_data)} (0x#{bin2hex(raw_data)})" if @enum.empty?
|
|
165
221
|
|
|
166
222
|
v = int_to_enum(der_to_int_value(raw_data), check_enum: false)
|
|
167
|
-
" #{v} (0x#{raw_data
|
|
223
|
+
" #{v} (0x#{bin2hex(raw_data)})"
|
|
168
224
|
end
|
|
169
225
|
end
|
|
170
226
|
end
|
data/lib/rasn1/types/null.rb
CHANGED
|
@@ -9,11 +9,14 @@
|
|
|
9
9
|
module RASN1
|
|
10
10
|
module Types
|
|
11
11
|
# ASN.1 Null
|
|
12
|
+
#
|
|
13
|
+
# This type is a placeholder when a value is not mandatory (in a {Choice}, by example).
|
|
12
14
|
# @author Sylvain Daubert
|
|
13
15
|
class Null < Primitive
|
|
14
16
|
# Null id value
|
|
15
17
|
ID = 0x05
|
|
16
18
|
|
|
19
|
+
# @param level [Integer]
|
|
17
20
|
# @return [String]
|
|
18
21
|
def inspect(level=0)
|
|
19
22
|
str = common_inspect(level)[0..-2] # remove terminal ':'
|
|
@@ -21,15 +24,15 @@ module RASN1
|
|
|
21
24
|
str
|
|
22
25
|
end
|
|
23
26
|
|
|
24
|
-
# @return [Boolean]
|
|
25
27
|
# Build only if not optional
|
|
28
|
+
# @return [Boolean]
|
|
26
29
|
def can_build?
|
|
27
30
|
!optional?
|
|
28
31
|
end
|
|
29
32
|
|
|
30
33
|
# Check +der+ string
|
|
31
|
-
# @param [String]
|
|
32
|
-
# @param [::Boolean]
|
|
34
|
+
# @param der [String]
|
|
35
|
+
# @param ber [::Boolean]
|
|
33
36
|
# @return [void]
|
|
34
37
|
# @raise [ASN1Error] +der+ is not empty
|
|
35
38
|
def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
|
|
@@ -41,6 +44,7 @@ module RASN1
|
|
|
41
44
|
|
|
42
45
|
private
|
|
43
46
|
|
|
47
|
+
# @return [String]
|
|
44
48
|
def value_to_der
|
|
45
49
|
''
|
|
46
50
|
end
|
|
@@ -9,7 +9,14 @@
|
|
|
9
9
|
module RASN1
|
|
10
10
|
module Types
|
|
11
11
|
# ASN.1 Numeric String
|
|
12
|
+
#
|
|
13
|
+
# A NUMERIC STRING is an {OctetString} limited to numeric digit.
|
|
14
|
+
# @example Numeric string
|
|
15
|
+
# ns = RASN1::Types::NumrericString.new(value: "123")
|
|
16
|
+
# ns.to_der #=> "\x12\x03123"
|
|
17
|
+
# RASN1.parse(ns.to_der).value #=> "123"
|
|
12
18
|
# @author Sylvain Daubert
|
|
19
|
+
# @author LemonTree55
|
|
13
20
|
class NumericString < OctetString
|
|
14
21
|
# NumericString id value
|
|
15
22
|
ID = 18
|
|
@@ -23,10 +30,11 @@ module RASN1
|
|
|
23
30
|
end
|
|
24
31
|
|
|
25
32
|
# Make string value from +der+ string
|
|
26
|
-
# @param [String]
|
|
27
|
-
# @param [::Boolean]
|
|
33
|
+
# @param der [String]
|
|
34
|
+
# @param ber [::Boolean]
|
|
28
35
|
# @return [void]
|
|
29
36
|
# @raise [ASN1Error] invalid characters detected
|
|
37
|
+
# @raise [ASN1Error] invalid character in string
|
|
30
38
|
def der_to_value(der, ber: false)
|
|
31
39
|
super
|
|
32
40
|
check_characters
|
|
@@ -34,11 +42,15 @@ module RASN1
|
|
|
34
42
|
|
|
35
43
|
private
|
|
36
44
|
|
|
45
|
+
# @return [String]
|
|
46
|
+
# @raise [ASN1Error] invalid character in string
|
|
37
47
|
def value_to_der
|
|
38
48
|
check_characters
|
|
39
49
|
@value.to_s.b
|
|
40
50
|
end
|
|
41
51
|
|
|
52
|
+
# @return [void]
|
|
53
|
+
# @raise [ASN1Error] invalid character in string
|
|
42
54
|
def check_characters
|
|
43
55
|
raise ASN1Error, "NUMERIC STRING #{@name}: invalid character: '#{$1}'" if @value.to_s =~ INVALID_CHARS
|
|
44
56
|
end
|
|
@@ -9,6 +9,15 @@
|
|
|
9
9
|
module RASN1
|
|
10
10
|
module Types
|
|
11
11
|
# ASN.1 Object ID
|
|
12
|
+
#
|
|
13
|
+
# An OBJECT ID provides unique identifiers.
|
|
14
|
+
#
|
|
15
|
+
# Object Id are shown as numbered dotted strings, like +0.1.2.1256.1+. First number is in range [0-2], the second
|
|
16
|
+
# in range [0-39]. Others are not limited.
|
|
17
|
+
#
|
|
18
|
+
# @example Object id
|
|
19
|
+
# oid = RASN1::Types::ObjectId.new(value: "0.2.145.65589.1")
|
|
20
|
+
# oid.to_der #=> "\x06\a\x02\x81\x11\x84\x805\x01"
|
|
12
21
|
# @author Sylvain Daubert
|
|
13
22
|
# @author LemonTree55
|
|
14
23
|
class ObjectId < Primitive
|
|
@@ -16,8 +25,8 @@ module RASN1
|
|
|
16
25
|
ID = 6
|
|
17
26
|
|
|
18
27
|
# Make object id value from +der+ string
|
|
19
|
-
# @param [String]
|
|
20
|
-
# @param [::Boolean]
|
|
28
|
+
# @param der [String]
|
|
29
|
+
# @param ber [::Boolean]
|
|
21
30
|
# @return [void]
|
|
22
31
|
def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
|
|
23
32
|
bytes = der.unpack('C*')
|
|
@@ -41,6 +50,7 @@ module RASN1
|
|
|
41
50
|
|
|
42
51
|
private
|
|
43
52
|
|
|
53
|
+
# @return [String]
|
|
44
54
|
# @raise [ASN1Error]
|
|
45
55
|
def value_to_der
|
|
46
56
|
ids = @value.to_s.split('.').map(&:to_i)
|
|
@@ -59,8 +69,9 @@ module RASN1
|
|
|
59
69
|
octets.pack('C*')
|
|
60
70
|
end
|
|
61
71
|
|
|
62
|
-
# @param [Array
|
|
63
|
-
# @
|
|
72
|
+
# @param ids [Array<::Integer>]
|
|
73
|
+
# @return [void]
|
|
74
|
+
# @raise [ASN1Error] one in two first ids are out of range
|
|
64
75
|
def check_first_ids(ids)
|
|
65
76
|
raise ASN1Error, "OBJECT ID #{@name}: first subidentifier should be less than 3" if ids[0] > 2
|
|
66
77
|
raise ASN1Error, "OBJECT ID #{@name}: second subidentifier should be less than 40" if (ids[0] < 2) && (ids[1] > 39)
|
|
@@ -21,7 +21,7 @@ module RASN1
|
|
|
21
21
|
# OctetString id value
|
|
22
22
|
ID = 4
|
|
23
23
|
|
|
24
|
-
# @param [::Integer]
|
|
24
|
+
# @param level [::Integer]
|
|
25
25
|
# @return [String]
|
|
26
26
|
def inspect(level=0)
|
|
27
27
|
str = common_inspect(level)
|
|
@@ -29,8 +29,8 @@ module RASN1
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
# Make string value from +der+ string. Force encoding to UTF-8
|
|
32
|
-
# @param [String]
|
|
33
|
-
# @param [::Boolean]
|
|
32
|
+
# @param der [String]
|
|
33
|
+
# @param ber [::Boolean]
|
|
34
34
|
# @return [void]
|
|
35
35
|
# @since 0.15.0 Handle ENCODING constant, if defined by subclass
|
|
36
36
|
def der_to_value(der, ber: false)
|