rasn1 0.6.8 → 0.9.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 +11 -3
- data/lib/rasn1/model.rb +185 -98
- data/lib/rasn1/types/any.rb +37 -22
- data/lib/rasn1/types/base.rb +217 -171
- data/lib/rasn1/types/bit_string.rb +44 -46
- data/lib/rasn1/types/boolean.rb +22 -14
- data/lib/rasn1/types/choice.rb +11 -16
- data/lib/rasn1/types/constructed.rb +7 -9
- data/lib/rasn1/types/enumerated.rb +10 -15
- data/lib/rasn1/types/generalized_time.rb +105 -64
- data/lib/rasn1/types/ia5string.rb +8 -6
- data/lib/rasn1/types/integer.rb +89 -81
- data/lib/rasn1/types/null.rb +11 -10
- data/lib/rasn1/types/numeric_string.rb +7 -7
- data/lib/rasn1/types/object_id.rb +19 -49
- data/lib/rasn1/types/octet_string.rb +6 -6
- data/lib/rasn1/types/primitive.rb +2 -1
- data/lib/rasn1/types/printable_string.rb +8 -7
- data/lib/rasn1/types/sequence.rb +39 -8
- data/lib/rasn1/types/sequence_of.rb +55 -41
- data/lib/rasn1/types/set.rb +4 -2
- data/lib/rasn1/types/set_of.rb +4 -3
- data/lib/rasn1/types/utc_time.rb +7 -5
- data/lib/rasn1/types/utf8_string.rb +7 -5
- data/lib/rasn1/types/visible_string.rb +4 -3
- data/lib/rasn1/types.rb +54 -24
- data/lib/rasn1/version.rb +3 -1
- data/lib/rasn1.rb +8 -7
- metadata +27 -51
- data/.gitignore +0 -11
- data/.rubocop.yml +0 -28
- data/.travis.yml +0 -9
- data/Gemfile +0 -4
- data/Rakefile +0 -12
- data/rasn1.gemspec +0 -32
data/lib/rasn1/types/base.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RASN1
|
2
4
|
module Types
|
3
|
-
|
4
5
|
# @abstract This is base class for all ASN.1 types.
|
5
6
|
#
|
6
7
|
# Subclasses SHOULD define:
|
7
|
-
# *
|
8
|
+
# * an ID constant defining ASN.1 BER/DER identification number,
|
8
9
|
# * a private method {#value_to_der} converting its {#value} to DER,
|
9
10
|
# * a private method {#der_to_value} converting DER into {#value}.
|
10
11
|
#
|
@@ -12,15 +13,15 @@ module RASN1
|
|
12
13
|
# An optional value may be defined using +:optional+ key from {#initialize}:
|
13
14
|
# Integer.new(:int, optional: true)
|
14
15
|
# An optional value implies:
|
15
|
-
# * while parsing, if decoded
|
16
|
-
# is raised, and parser tries
|
16
|
+
# * while parsing, if decoded ID is not optional expected ID, no {ASN1Error}
|
17
|
+
# is raised, and parser tries next field,
|
17
18
|
# * while encoding, if {#value} is +nil+, this value is not encoded.
|
18
19
|
# ==Define a default value
|
19
20
|
# A default value may be defined using +:default+ key from {#initialize}:
|
20
21
|
# Integer.new(:int, default: 0)
|
21
22
|
# A default value implies:
|
22
|
-
# * while parsing, if decoded
|
23
|
-
# and parser sets default value to this
|
23
|
+
# * while parsing, if decoded ID is not expected one, no {ASN1Error} is raised
|
24
|
+
# and parser sets default value to this ID. Then parser tries next field,
|
24
25
|
# * while encoding, if {#value} is equal to default value, this value is not
|
25
26
|
# encoded.
|
26
27
|
# ==Define a tagged value
|
@@ -43,17 +44,21 @@ module RASN1
|
|
43
44
|
# Implicit tagged values may also be defined:
|
44
45
|
# ctype_implicit = RASN1::Types::Integer.new(implicit: 0)
|
45
46
|
# @author Sylvain Daubert
|
46
|
-
class Base
|
47
|
-
# Allowed ASN.1
|
47
|
+
class Base # rubocop:disable Metrics/ClassLength
|
48
|
+
# Allowed ASN.1 classes
|
48
49
|
CLASSES = {
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
universal: 0x00,
|
51
|
+
application: 0x40,
|
52
|
+
context: 0x80,
|
53
|
+
private: 0xc0
|
54
|
+
}.freeze
|
54
55
|
|
55
|
-
#
|
56
|
-
|
56
|
+
# Binary mask to get class
|
57
|
+
# @private
|
58
|
+
CLASS_MASK = 0xc0
|
59
|
+
|
60
|
+
# @private first octet identifier for multi-octets identifier
|
61
|
+
MULTI_OCTETS_ID = 0x1f
|
57
62
|
|
58
63
|
# Length value for indefinite length
|
59
64
|
INDEFINITE_LENGTH = 0x80
|
@@ -64,19 +69,18 @@ module RASN1
|
|
64
69
|
attr_reader :asn1_class
|
65
70
|
# @return [Object,nil] default value, if defined
|
66
71
|
attr_reader :default
|
67
|
-
# @return [Object]
|
68
|
-
attr_writer :value
|
69
72
|
|
70
73
|
# Get ASN.1 type
|
71
74
|
# @return [String]
|
72
75
|
def self.type
|
73
76
|
return @type if defined? @type
|
77
|
+
|
74
78
|
@type = self.to_s.gsub(/.*::/, '').gsub(/([a-z0-9])([A-Z])/, '\1 \2').upcase
|
75
79
|
end
|
76
80
|
|
77
81
|
# Get ASN.1 type used to encode this one
|
78
82
|
# @return [String]
|
79
|
-
def self.
|
83
|
+
def self.encoded_type
|
80
84
|
type
|
81
85
|
end
|
82
86
|
|
@@ -91,68 +95,50 @@ module RASN1
|
|
91
95
|
obj
|
92
96
|
end
|
93
97
|
|
94
|
-
|
95
|
-
# @
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
|
107
|
-
# @option options [::String] :name name for this node
|
108
|
-
# @overload initialize(value, options={})
|
109
|
-
# @param [Object] value value to set for this ASN.1 object
|
110
|
-
# @param [Hash] options
|
111
|
-
# @option options [Symbol] :class ASN.1 tag class. Default value is +:universal+.
|
112
|
-
# If +:explicit+ or +:implicit:+ is defined, default value is +:context+.
|
113
|
-
# @option options [::Boolean] :optional define this tag as optional. Default
|
114
|
-
# is +false+
|
115
|
-
# @option options [Object] :default default value for DEFAULT tag
|
116
|
-
# @option options [::Integer] :implicit define an IMPLICIT tagged type
|
117
|
-
# @option options [::Integer] :explicit define an EXPLICIT tagged type
|
118
|
-
# @option options [::Boolean] :constructed if +true+, set type as constructed.
|
119
|
-
# May only be used when +:explicit+ is defined, else it is discarded.
|
120
|
-
# @option options [::String] :name name for this node
|
121
|
-
def initialize(value_or_options={}, options={})
|
98
|
+
# @param [Hash] options
|
99
|
+
# @option options [Symbol] :class ASN.1 class. Default value is +:universal+.
|
100
|
+
# If +:explicit+ or +:implicit:+ is defined, default value is +:context+.
|
101
|
+
# @option options [::Boolean] :optional define this tag as optional. Default
|
102
|
+
# is +false+
|
103
|
+
# @option options [Object] :default default value (ASN.1 DEFAULT)
|
104
|
+
# @option options [Object] :value value to set
|
105
|
+
# @option options [::Integer] :implicit define an IMPLICIT tagged type
|
106
|
+
# @option options [::Integer] :explicit define an EXPLICIT tagged type
|
107
|
+
# @option options [::Boolean] :constructed if +true+, set type as constructed.
|
108
|
+
# May only be used when +:explicit+ is defined, else it is discarded.
|
109
|
+
# @option options [::String] :name name for this node
|
110
|
+
def initialize(options={})
|
122
111
|
@constructed = nil
|
123
|
-
|
124
|
-
set_options value_or_options
|
125
|
-
else
|
126
|
-
set_options options
|
127
|
-
@value = value_or_options
|
128
|
-
end
|
112
|
+
set_options options
|
129
113
|
end
|
130
114
|
|
131
|
-
# Used by +#dup+ and +#clone+. Deep copy @value.
|
132
|
-
def initialize_copy(
|
133
|
-
@value =
|
134
|
-
|
135
|
-
|
136
|
-
else
|
137
|
-
@value.dup
|
138
|
-
end
|
139
|
-
@default = case
|
140
|
-
when NilClass, TrueClass, FalseClass, Integer
|
141
|
-
@default
|
142
|
-
else
|
143
|
-
@default.dup
|
144
|
-
end
|
115
|
+
# Used by +#dup+ and +#clone+. Deep copy @value and @default.
|
116
|
+
def initialize_copy(_other)
|
117
|
+
@value = @value.dup
|
118
|
+
@no_value = @no_value.dup
|
119
|
+
@default = @default.dup
|
145
120
|
end
|
146
121
|
|
147
122
|
# Get value or default value
|
148
123
|
def value
|
149
|
-
if
|
150
|
-
@default
|
151
|
-
else
|
124
|
+
if value?
|
152
125
|
@value
|
126
|
+
else
|
127
|
+
@default
|
153
128
|
end
|
154
129
|
end
|
155
130
|
|
131
|
+
# Set value. If +val+ is +nil+, unset value
|
132
|
+
# @param [Object,nil] val
|
133
|
+
def value=(val)
|
134
|
+
set_value(val)
|
135
|
+
end
|
136
|
+
|
137
|
+
# @abstract Define 'void' value (i.e. 'value' when no value was set)
|
138
|
+
def void_value
|
139
|
+
''
|
140
|
+
end
|
141
|
+
|
156
142
|
# @return [::Boolean]
|
157
143
|
def optional?
|
158
144
|
@optional
|
@@ -168,21 +154,21 @@ module RASN1
|
|
168
154
|
# @return [::Boolean,nil] return +nil+ if not tagged, return +true+
|
169
155
|
# if explicit, else +false+
|
170
156
|
def explicit?
|
171
|
-
|
157
|
+
defined?(@tag) ? @tag == :explicit : nil
|
172
158
|
end
|
173
159
|
|
174
160
|
# Say if a tagged type is implicit
|
175
161
|
# @return [::Boolean,nil] return +nil+ if not tagged, return +true+
|
176
162
|
# if implicit, else +false+
|
177
163
|
def implicit?
|
178
|
-
|
164
|
+
defined?(@tag) ? @tag == :implicit : nil
|
179
165
|
end
|
180
166
|
|
181
167
|
# @abstract This method SHOULD be partly implemented by subclasses, which
|
182
168
|
# SHOULD respond to +#value_to_der+.
|
183
169
|
# @return [String] DER-formated string
|
184
170
|
def to_der
|
185
|
-
|
171
|
+
build
|
186
172
|
end
|
187
173
|
|
188
174
|
# @return [::Boolean] +true+ if this is a primitive type
|
@@ -192,7 +178,7 @@ module RASN1
|
|
192
178
|
|
193
179
|
# @return [::Boolean] +true+ if this is a constructed type
|
194
180
|
def constructed?
|
195
|
-
|
181
|
+
(self.class < Constructed) || !!@constructed
|
196
182
|
end
|
197
183
|
|
198
184
|
# Get ASN.1 type
|
@@ -201,17 +187,10 @@ module RASN1
|
|
201
187
|
self.class.type
|
202
188
|
end
|
203
189
|
|
204
|
-
# Get
|
190
|
+
# Get identifier value
|
205
191
|
# @return [Integer]
|
206
|
-
def
|
207
|
-
|
208
|
-
self.class::ASN1_PC
|
209
|
-
elsif @constructed # true
|
210
|
-
Constructed::ASN1_PC
|
211
|
-
else # false
|
212
|
-
0
|
213
|
-
end
|
214
|
-
tag_value | CLASSES[@asn1_class] | pc
|
192
|
+
def id
|
193
|
+
id_value
|
215
194
|
end
|
216
195
|
|
217
196
|
# @abstract This method SHOULD be partly implemented by subclasses to parse
|
@@ -222,13 +201,15 @@ module RASN1
|
|
222
201
|
# @return [Integer] total number of parsed bytes
|
223
202
|
# @raise [ASN1Error] error on parsing
|
224
203
|
def parse!(der, ber: false)
|
225
|
-
return 0 unless
|
204
|
+
return 0 unless check_id(der)
|
226
205
|
|
227
|
-
|
206
|
+
id_size = Types.decode_identifier_octets(der).last
|
207
|
+
total_length, data = get_data(der[id_size..-1], ber)
|
208
|
+
total_length += id_size
|
209
|
+
@no_value = false
|
228
210
|
if explicit?
|
229
|
-
# Delegate to #explicit type to generate sub-
|
211
|
+
# Delegate to #explicit type to generate sub-value
|
230
212
|
type = explicit_type
|
231
|
-
type.value = @value
|
232
213
|
type.parse!(data)
|
233
214
|
@value = type.value
|
234
215
|
else
|
@@ -247,11 +228,9 @@ module RASN1
|
|
247
228
|
# @param [Integer] level
|
248
229
|
# @return [String]
|
249
230
|
def inspect(level=0)
|
250
|
-
str =
|
251
|
-
str << '
|
252
|
-
str <<
|
253
|
-
str << "#{type}: #{value.inspect}"
|
254
|
-
str << " OPTIONAL" if optional?
|
231
|
+
str = common_inspect(level)
|
232
|
+
str << ' ' << inspect_value
|
233
|
+
str << ' OPTIONAL' if optional?
|
255
234
|
str << " DEFAULT #{@default}" unless @default.nil?
|
256
235
|
str
|
257
236
|
end
|
@@ -265,6 +244,34 @@ module RASN1
|
|
265
244
|
|
266
245
|
private
|
267
246
|
|
247
|
+
def pc_bit
|
248
|
+
if @constructed.nil?
|
249
|
+
self.class::ASN1_PC
|
250
|
+
elsif @constructed # true
|
251
|
+
Constructed::ASN1_PC
|
252
|
+
else # false
|
253
|
+
Primitive::ASN1_PC
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def common_inspect(level)
|
258
|
+
lvl = level >= 0 ? level : 0
|
259
|
+
str = ' ' * lvl
|
260
|
+
str << "#{@name} " unless @name.nil?
|
261
|
+
str << asn1_class.to_s.upcase << ' ' unless asn1_class == :universal
|
262
|
+
str << "[#{id}] EXPLICIT " if explicit?
|
263
|
+
str << "[#{id}] IMPLICIT " if implicit?
|
264
|
+
str << "#{type}:"
|
265
|
+
end
|
266
|
+
|
267
|
+
def inspect_value
|
268
|
+
if value?
|
269
|
+
value.inspect
|
270
|
+
else
|
271
|
+
'(NO VALUE)'
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
268
275
|
def value_to_der
|
269
276
|
case @value
|
270
277
|
when Base
|
@@ -274,68 +281,82 @@ module RASN1
|
|
274
281
|
end
|
275
282
|
end
|
276
283
|
|
277
|
-
def der_to_value(der, ber:false)
|
284
|
+
def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
|
278
285
|
@value = der
|
279
286
|
end
|
280
287
|
|
281
|
-
def set_options(options)
|
288
|
+
def set_options(options) # rubocop:disable Naming/AccessorMethodName
|
282
289
|
set_class options[:class]
|
283
290
|
set_optional options[:optional]
|
284
291
|
set_default options[:default]
|
285
292
|
set_tag options
|
286
|
-
|
293
|
+
set_value options[:value]
|
287
294
|
@name = options[:name]
|
295
|
+
@options = options
|
288
296
|
end
|
289
297
|
|
290
|
-
def set_class(asn1_class)
|
298
|
+
def set_class(asn1_class) # rubocop:disable Naming/AccessorMethodName
|
291
299
|
case asn1_class
|
292
300
|
when nil
|
293
301
|
@asn1_class = :universal
|
294
302
|
when Symbol
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
raise ClassError
|
299
|
-
end
|
303
|
+
raise ClassError unless CLASSES.key? asn1_class
|
304
|
+
|
305
|
+
@asn1_class = asn1_class
|
300
306
|
else
|
301
307
|
raise ClassError
|
302
308
|
end
|
303
309
|
end
|
304
310
|
|
305
|
-
def set_optional(optional)
|
311
|
+
def set_optional(optional) # rubocop:disable Naming/AccessorMethodName
|
306
312
|
@optional = !!optional
|
307
313
|
end
|
308
314
|
|
309
|
-
def set_default(default)
|
315
|
+
def set_default(default) # rubocop:disable Naming/AccessorMethodName
|
310
316
|
@default = default
|
311
317
|
end
|
312
318
|
|
313
319
|
# handle undocumented option +:tag_value+, used internally by
|
314
320
|
# {RASN1.parse} to parse non-universal class tags.
|
315
|
-
def set_tag(options)
|
321
|
+
def set_tag(options) # rubocop:disable Naming/AccessorMethodName
|
316
322
|
if options[:explicit]
|
317
323
|
@tag = :explicit
|
318
|
-
@
|
324
|
+
@id_value = options[:explicit]
|
319
325
|
@constructed = options[:constructed]
|
320
326
|
elsif options[:implicit]
|
321
327
|
@tag = :implicit
|
322
|
-
@
|
328
|
+
@id_value = options[:implicit]
|
323
329
|
@constructed = options[:constructed]
|
324
330
|
elsif options[:tag_value]
|
325
|
-
@
|
331
|
+
@id_value = options[:tag_value]
|
326
332
|
@constructed = options[:constructed]
|
327
333
|
end
|
328
334
|
|
329
335
|
@asn1_class = :context if defined?(@tag) && (@asn1_class == :universal)
|
330
336
|
end
|
331
337
|
|
332
|
-
def
|
333
|
-
|
334
|
-
|
338
|
+
def set_value(value) # rubocop:disable Naming/AccessorMethodName
|
339
|
+
if value.nil?
|
340
|
+
@no_value = true
|
341
|
+
@value = void_value
|
342
|
+
else
|
343
|
+
@no_value = false
|
344
|
+
@value = value
|
345
|
+
end
|
346
|
+
value
|
347
|
+
end
|
348
|
+
|
349
|
+
def value?
|
350
|
+
!@no_value
|
351
|
+
end
|
352
|
+
|
353
|
+
def can_build?
|
354
|
+
(@default.nil? || (value? && (@value != @default))) &&
|
355
|
+
(!optional? || value?)
|
335
356
|
end
|
336
357
|
|
337
|
-
def
|
338
|
-
if
|
358
|
+
def build
|
359
|
+
if can_build?
|
339
360
|
if explicit?
|
340
361
|
v = explicit_type
|
341
362
|
v.value = @value
|
@@ -343,35 +364,52 @@ module RASN1
|
|
343
364
|
else
|
344
365
|
encoded_value = value_to_der
|
345
366
|
end
|
346
|
-
|
367
|
+
encode_identifier_octets << encode_size(encoded_value.size) << encoded_value
|
347
368
|
else
|
348
369
|
''
|
349
370
|
end
|
350
371
|
end
|
351
372
|
|
352
|
-
def
|
353
|
-
return @
|
373
|
+
def id_value
|
374
|
+
return @id_value if defined? @id_value
|
354
375
|
|
355
|
-
self.class::
|
376
|
+
self.class::ID
|
356
377
|
end
|
357
378
|
|
358
|
-
def
|
359
|
-
|
360
|
-
|
379
|
+
def encode_identifier_octets
|
380
|
+
id2octets.pack('C*')
|
381
|
+
end
|
382
|
+
|
383
|
+
def id2octets
|
384
|
+
first_octet = CLASSES[asn1_class] | pc_bit
|
385
|
+
if id < MULTI_OCTETS_ID
|
386
|
+
[first_octet | id]
|
361
387
|
else
|
362
|
-
|
388
|
+
[first_octet | MULTI_OCTETS_ID] + unsigned_to_chained_octets(id)
|
363
389
|
end
|
364
390
|
end
|
365
391
|
|
392
|
+
# Encode an unsigned integer on multiple octets.
|
393
|
+
# Value is encoded on bit 6-0 of each octet, bit 7(MSB) indicates wether
|
394
|
+
# further octets follow.
|
395
|
+
def unsigned_to_chained_octets(value)
|
396
|
+
ary = []
|
397
|
+
while value.positive?
|
398
|
+
ary.unshift(value & 0x7f | 0x80)
|
399
|
+
value >>= 7
|
400
|
+
end
|
401
|
+
ary[-1] &= 0x7f
|
402
|
+
ary
|
403
|
+
end
|
404
|
+
|
366
405
|
def encode_size(size)
|
367
406
|
if size >= INDEFINITE_LENGTH
|
368
407
|
bytes = []
|
369
408
|
while size > 255
|
370
|
-
bytes
|
409
|
+
bytes.unshift(size & 0xff)
|
371
410
|
size >>= 8
|
372
411
|
end
|
373
|
-
bytes
|
374
|
-
bytes.reverse!
|
412
|
+
bytes.unshift(size)
|
375
413
|
bytes.unshift(INDEFINITE_LENGTH | bytes.size)
|
376
414
|
bytes.pack('C*')
|
377
415
|
else
|
@@ -379,84 +417,92 @@ module RASN1
|
|
379
417
|
end
|
380
418
|
end
|
381
419
|
|
382
|
-
def
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
false
|
420
|
+
def check_id(der)
|
421
|
+
expected_id = encode_identifier_octets
|
422
|
+
real_id = der[0, expected_id.size]
|
423
|
+
return true if real_id == expected_id
|
424
|
+
|
425
|
+
if optional?
|
426
|
+
@no_value = true
|
427
|
+
@value = void_value
|
428
|
+
elsif !@default.nil?
|
429
|
+
@value = @default
|
393
430
|
else
|
394
|
-
|
431
|
+
raise_id_error(der)
|
395
432
|
end
|
433
|
+
false
|
396
434
|
end
|
397
435
|
|
398
436
|
def get_data(der, ber)
|
399
|
-
length = der
|
437
|
+
length = der.unpack1('C').to_i
|
400
438
|
length_length = 0
|
401
439
|
|
402
440
|
if length == INDEFINITE_LENGTH
|
403
|
-
|
404
|
-
|
405
|
-
"forbidden for primitive types"
|
406
|
-
else
|
407
|
-
if ber
|
408
|
-
raise NotImplementedError, "TAG: indefinite length not " \
|
409
|
-
"supported yet"
|
410
|
-
else
|
411
|
-
raise ASN1Error, "TAG: indefinite length forbidden in DER " \
|
412
|
-
"encoding"
|
413
|
-
end
|
414
|
-
end
|
415
|
-
elsif length < INDEFINITE_LENGTH
|
416
|
-
data = der[2, length]
|
417
|
-
else
|
441
|
+
raise_on_indefinite_length(ber)
|
442
|
+
elsif length > INDEFINITE_LENGTH
|
418
443
|
length_length = length & 0x7f
|
419
|
-
length = der[
|
420
|
-
|
421
|
-
data = der[2 + length_length, length]
|
444
|
+
length = der[1, length_length].unpack('C*')
|
445
|
+
.reduce(0) { |len, b| (len << 8) | b }
|
422
446
|
end
|
447
|
+
data = der[1 + length_length, length]
|
423
448
|
|
424
|
-
total_length =
|
425
|
-
total_length += length_length if length_length
|
449
|
+
total_length = 1 + length
|
450
|
+
total_length += length_length if length_length.positive?
|
426
451
|
|
427
452
|
[total_length, data]
|
428
453
|
end
|
429
454
|
|
455
|
+
def raise_on_indefinite_length(ber)
|
456
|
+
if primitive?
|
457
|
+
raise ASN1Error, "malformed #{type}: indefinite length " \
|
458
|
+
'forbidden for primitive types'
|
459
|
+
elsif ber
|
460
|
+
raise NotImplementedError, 'indefinite length not supported'
|
461
|
+
else
|
462
|
+
raise ASN1Error, 'indefinite length forbidden in DER encoding'
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
430
466
|
def explicit_type
|
431
467
|
self.class.new
|
432
468
|
end
|
433
469
|
|
434
|
-
def
|
435
|
-
msg = name.nil? ? '' : "#{name}: "
|
436
|
-
msg << "Expected #{self2name} but get #{
|
470
|
+
def raise_id_error(der)
|
471
|
+
msg = name.nil? ? +'' : +"#{name}: "
|
472
|
+
msg << "Expected #{self2name} but get #{der2name(der)}"
|
437
473
|
raise ASN1Error, msg
|
438
474
|
end
|
439
475
|
|
476
|
+
def class_from_numeric_id(id)
|
477
|
+
CLASSES.key(id & CLASS_MASK)
|
478
|
+
end
|
479
|
+
|
440
480
|
def self2name
|
441
|
-
name =
|
442
|
-
name << " #{tag & Constructed::ASN1_PC > 0 ? 'CONSTRUCTED' : 'PRIMITIVE'}"
|
481
|
+
name = +"#{asn1_class.to_s.upcase} #{constructed? ? 'CONSTRUCTED' : 'PRIMITIVE'}"
|
443
482
|
if implicit? || explicit?
|
444
|
-
name << ' 0x%
|
483
|
+
name << ' 0x%X (0x%s)' % [id, bin2hex(encode_identifier_octets)]
|
445
484
|
else
|
446
485
|
name << ' ' << self.class.type
|
447
486
|
end
|
448
487
|
end
|
449
488
|
|
450
|
-
def
|
451
|
-
return 'no
|
489
|
+
def der2name(der)
|
490
|
+
return 'no ID' if der.nil? || der.empty?
|
491
|
+
|
492
|
+
asn1_class, pc, id, id_size = Types.decode_identifier_octets(der)
|
493
|
+
name = +"#{asn1_class.to_s.upcase} #{pc.to_s.upcase}"
|
494
|
+
type = find_type(id)
|
495
|
+
name << " #{type.nil? ? '0x%X (0x%s)' % [id, bin2hex(der[0...id_size])] : type.encoded_type}"
|
496
|
+
end
|
497
|
+
|
498
|
+
def find_type(id)
|
499
|
+
Types.constants.map { |c| Types.const_get(c) }
|
500
|
+
.select { |klass| klass < Primitive || klass < Constructed }
|
501
|
+
.find { |klass| klass::ID == id }
|
502
|
+
end
|
452
503
|
|
453
|
-
|
454
|
-
|
455
|
-
name << " #{itag & Constructed::ASN1_PC > 0 ? 'CONSTRUCTED' : 'PRIMITIVE'}"
|
456
|
-
type = Types.constants.map { |c| Types.const_get(c) }.
|
457
|
-
select { |klass| klass < Primitive || klass < Constructed }.
|
458
|
-
find { |klass| klass::TAG == itag & 0x1f }
|
459
|
-
name << " #{type.nil? ? "0x%02X (0x%02X)" % [itag & 0x1f, itag] : type.encode_type }"
|
504
|
+
def bin2hex(str)
|
505
|
+
str.unpack1('H*')
|
460
506
|
end
|
461
507
|
end
|
462
508
|
end
|