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