rasn1 0.16.2 → 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.
- checksums.yaml +4 -4
- data/lib/rasn1/errors.rb +2 -2
- data/lib/rasn1/model.rb +113 -78
- data/lib/rasn1/tracer.rb +25 -5
- 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 +35 -8
- 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 +4 -3
- metadata +3 -3
|
@@ -9,7 +9,18 @@
|
|
|
9
9
|
module RASN1
|
|
10
10
|
module Types
|
|
11
11
|
# ASN.1 Bit String
|
|
12
|
+
#
|
|
13
|
+
# A BIT STRING is a primitive ASN.1 type, able to embbed data whose length is not multiple of a byte.
|
|
14
|
+
#
|
|
15
|
+
# To specify a non byte multiple length, +:bit_length+ option must be used.
|
|
16
|
+
#
|
|
17
|
+
# @example Simple bit string
|
|
18
|
+
# # A 4-bit length bit string, with value 1000b
|
|
19
|
+
# bs = RASN1::Types::BitString.new(value: "\x80", bit_length: 4)
|
|
20
|
+
# # As DER/BER encode data on bytes, such encodings specify unused part in binary string
|
|
21
|
+
# bs.to_der #=> "\x03\x02\x04\x80"
|
|
12
22
|
# @author Sylvain Daubert
|
|
23
|
+
# @author LemonTree55
|
|
13
24
|
class BitString < Primitive
|
|
14
25
|
# BitString id value
|
|
15
26
|
ID = 3
|
|
@@ -17,10 +28,9 @@ module RASN1
|
|
|
17
28
|
# @return [Integer]
|
|
18
29
|
attr_writer :bit_length
|
|
19
30
|
|
|
20
|
-
#
|
|
31
|
+
# @!macro type_initialize
|
|
21
32
|
# @option options [Object] :bit_length default bit_length value. Should be
|
|
22
33
|
# present if +:default+ is set
|
|
23
|
-
# @see Base#initialize common options to all ASN.1 types
|
|
24
34
|
def initialize(options={})
|
|
25
35
|
super
|
|
26
36
|
if @default
|
|
@@ -40,7 +50,7 @@ module RASN1
|
|
|
40
50
|
end
|
|
41
51
|
end
|
|
42
52
|
|
|
43
|
-
# @param [Integer]
|
|
53
|
+
# @param level [Integer]
|
|
44
54
|
# @return [String]
|
|
45
55
|
def inspect(level=0)
|
|
46
56
|
str = common_inspect(level)
|
|
@@ -55,8 +65,8 @@ module RASN1
|
|
|
55
65
|
end
|
|
56
66
|
|
|
57
67
|
# Make value from DER/BER string. Also set {#bit_length}.
|
|
58
|
-
# @param [String]
|
|
59
|
-
# @param [::Boolean]
|
|
68
|
+
# @param der [String]
|
|
69
|
+
# @param ber [::Boolean]
|
|
60
70
|
# @return [void]
|
|
61
71
|
# @see Types::Base#der_to_value
|
|
62
72
|
def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
|
|
@@ -70,6 +80,7 @@ module RASN1
|
|
|
70
80
|
|
|
71
81
|
# @author Sylvain Daubert
|
|
72
82
|
# @author adfoster-r7
|
|
83
|
+
# @return [String]
|
|
73
84
|
def value_to_der
|
|
74
85
|
raise ASN1Error, "#{@name}: bit length is not set" if bit_length.nil?
|
|
75
86
|
|
|
@@ -89,6 +100,7 @@ module RASN1
|
|
|
89
100
|
der
|
|
90
101
|
end
|
|
91
102
|
|
|
103
|
+
# @return [String]
|
|
92
104
|
def generate_value_with_correct_length
|
|
93
105
|
value = (@value || '').dup.force_encoding('BINARY')
|
|
94
106
|
value << "\x00".b while value.length * 8 < @bit_length.to_i
|
|
@@ -98,6 +110,7 @@ module RASN1
|
|
|
98
110
|
value[0, max_len].to_s
|
|
99
111
|
end
|
|
100
112
|
|
|
113
|
+
# @return [BitString]
|
|
101
114
|
def explicit_type
|
|
102
115
|
self.class.new(name: name, value: @value, bit_length: @bit_length)
|
|
103
116
|
end
|
data/lib/rasn1/types/boolean.rb
CHANGED
|
@@ -9,7 +9,16 @@
|
|
|
9
9
|
module RASN1
|
|
10
10
|
module Types
|
|
11
11
|
# ASN.1 Boolean
|
|
12
|
+
#
|
|
13
|
+
# BOOLEAN is a primitive type to handle true or false values.
|
|
14
|
+
# @example Booelan
|
|
15
|
+
# bool = RASN1::Types::Boolean.new(value: true)
|
|
16
|
+
# bool2 = RASN1.parse(bool.to_der)
|
|
17
|
+
# bool2.class #=> RASN1::Types::Boolean
|
|
18
|
+
# bool3.value #=> true
|
|
19
|
+
#
|
|
12
20
|
# @author Sylvain Daubert
|
|
21
|
+
# @author LemonTree55
|
|
13
22
|
class Boolean < Primitive
|
|
14
23
|
# Boolean id value
|
|
15
24
|
ID = 0x01
|
|
@@ -25,8 +34,8 @@ module RASN1
|
|
|
25
34
|
end
|
|
26
35
|
|
|
27
36
|
# Make boolean value from DER/BER string.
|
|
28
|
-
# @param [String]
|
|
29
|
-
# @param [::Boolean]
|
|
37
|
+
# @param der [String]
|
|
38
|
+
# @param ber [::Boolean]
|
|
30
39
|
# @return [void]
|
|
31
40
|
# @see Types::Base#der_to_value
|
|
32
41
|
# @raise [ASN1Error] +der+ is not 1-byte long
|
|
@@ -49,14 +58,16 @@ module RASN1
|
|
|
49
58
|
|
|
50
59
|
private
|
|
51
60
|
|
|
61
|
+
# @return [String]
|
|
52
62
|
def value_to_der
|
|
53
63
|
[@value ? DER_TRUE : DER_FALSE].pack('C')
|
|
54
64
|
end
|
|
55
65
|
|
|
66
|
+
# @return [String]
|
|
56
67
|
def trace_data
|
|
57
68
|
return super if explicit?
|
|
58
69
|
|
|
59
|
-
" #{raw_data == "\x00".b ? 'FALSE' : 'TRUE'} (0x#{raw_data
|
|
70
|
+
" #{raw_data == "\x00".b ? 'FALSE' : 'TRUE'} (0x#{bin2hex(raw_data)})"
|
|
60
71
|
end
|
|
61
72
|
end
|
|
62
73
|
end
|
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,9 +98,13 @@ 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]
|
|
104
|
+
# @note
|
|
105
|
+
# Ruby 3.0: special handle for timezone
|
|
106
|
+
# * From 3.1: "Z" and "-0100" are supported
|
|
107
|
+
# * Below 3.1: should be "-01:00" or "+00:00"
|
|
97
108
|
def compute_tz(date_hour)
|
|
98
109
|
if date_hour.end_with?('Z')
|
|
99
110
|
date_hour.slice!(-1, 1)
|
|
@@ -106,6 +117,10 @@ module RASN1
|
|
|
106
117
|
end
|
|
107
118
|
end
|
|
108
119
|
|
|
120
|
+
# Set value in special case where fraction ends with 'Z'
|
|
121
|
+
# @param date_hour [String]
|
|
122
|
+
# @param fraction [String]
|
|
123
|
+
# @return [void]
|
|
109
124
|
def value_when_fraction_ends_with_z(date_hour, fraction)
|
|
110
125
|
fraction = fraction[0...-1]
|
|
111
126
|
date_hour << 'Z'
|
|
@@ -114,6 +129,10 @@ module RASN1
|
|
|
114
129
|
fix_value(fraction, frac_base)
|
|
115
130
|
end
|
|
116
131
|
|
|
132
|
+
# Set value in general case
|
|
133
|
+
# @param date_hour [String]
|
|
134
|
+
# @param fraction [String]
|
|
135
|
+
# @return [void]
|
|
117
136
|
def value_on_others_cases(date_hour, fraction)
|
|
118
137
|
match = fraction.match(/(\d+)([+-]\d+)/)
|
|
119
138
|
if match
|
|
@@ -127,11 +146,18 @@ module RASN1
|
|
|
127
146
|
fix_value(fraction, frac_base)
|
|
128
147
|
end
|
|
129
148
|
|
|
149
|
+
# Fix internal value with +fraction+, based on +frac_base+
|
|
150
|
+
# @param fraction [String]
|
|
151
|
+
# @param frac_base [::Integer]
|
|
152
|
+
# @return [void]
|
|
130
153
|
def fix_value(fraction, frac_base)
|
|
131
154
|
frac = ".#{fraction}".to_r * frac_base
|
|
132
155
|
@value = (@value + frac) unless fraction.nil?
|
|
133
156
|
end
|
|
134
157
|
|
|
158
|
+
# Compute fraction base from +date_hour+ string
|
|
159
|
+
# @param date_hour [String]
|
|
160
|
+
# @return [::Integer]
|
|
135
161
|
def compute_frac_base(date_hour)
|
|
136
162
|
case date_hour.size
|
|
137
163
|
when 10, 11
|
|
@@ -152,6 +178,7 @@ module RASN1
|
|
|
152
178
|
end
|
|
153
179
|
end
|
|
154
180
|
|
|
181
|
+
# @return [String]
|
|
155
182
|
def trace_data
|
|
156
183
|
return super if explicit?
|
|
157
184
|
|
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
|