rasn1 0.6.6 → 0.8.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 -2
- data/lib/rasn1.rb +7 -6
- data/lib/rasn1/model.rb +108 -59
- data/lib/rasn1/types.rb +49 -20
- data/lib/rasn1/types/any.rb +26 -16
- data/lib/rasn1/types/base.rb +146 -115
- data/lib/rasn1/types/bit_string.rb +20 -24
- data/lib/rasn1/types/boolean.rb +17 -14
- data/lib/rasn1/types/choice.rb +11 -16
- data/lib/rasn1/types/constructed.rb +9 -9
- data/lib/rasn1/types/enumerated.rb +4 -2
- data/lib/rasn1/types/generalized_time.rb +24 -26
- data/lib/rasn1/types/ia5string.rb +7 -5
- data/lib/rasn1/types/integer.rb +32 -45
- data/lib/rasn1/types/null.rb +8 -8
- data/lib/rasn1/types/numeric_string.rb +7 -7
- data/lib/rasn1/types/object_id.rb +18 -48
- 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 +21 -7
- data/lib/rasn1/types/sequence_of.rb +15 -13
- data/lib/rasn1/types/set.rb +4 -2
- data/lib/rasn1/types/set_of.rb +4 -3
- data/lib/rasn1/types/utc_time.rb +6 -4
- data/lib/rasn1/types/utf8_string.rb +6 -4
- data/lib/rasn1/types/visible_string.rb +4 -3
- data/lib/rasn1/version.rb +3 -1
- metadata +27 -50
- data/.gitignore +0 -11
- data/.rubocop.yml +0 -29
- data/.travis.yml +0 -9
- data/Gemfile +0 -4
- data/Rakefile +0 -12
- data/rasn1.gemspec +0 -32
data/lib/rasn1/types/any.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RASN1
|
2
4
|
module Types
|
3
|
-
|
4
5
|
# ASN.1 ANY: accepts any types
|
5
6
|
#
|
6
|
-
# If `any#value` is `nil
|
7
|
+
# If `any#value` is `nil` and Any object is not {#optional?}, `any` will be encoded as a {Null} object.
|
7
8
|
# @author Sylvain Daubert
|
8
9
|
class Any < Base
|
9
|
-
|
10
10
|
# @return [String] DER-formated string
|
11
11
|
def to_der
|
12
12
|
case @value
|
13
13
|
when Base, Model
|
14
14
|
@value.to_der
|
15
15
|
when nil
|
16
|
-
Null.new.to_der
|
16
|
+
optional? ? '' : Null.new.to_der
|
17
17
|
else
|
18
18
|
@value.to_s
|
19
19
|
end
|
@@ -25,24 +25,34 @@ module RASN1
|
|
25
25
|
# @param [Boolean] ber if +true+, accept BER encoding
|
26
26
|
# @return [Integer] total number of parsed bytes
|
27
27
|
def parse!(der, ber: false)
|
28
|
-
|
28
|
+
if der.nil? || der.empty?
|
29
|
+
return 0 if optional?
|
30
|
+
|
31
|
+
raise ASN1Error, 'Expected ANY but get nothing'
|
32
|
+
end
|
33
|
+
|
34
|
+
id_size = Types.decode_identifier_octets(der).last
|
35
|
+
total_length, = get_data(der[id_size..-1], ber)
|
36
|
+
total_length += id_size
|
37
|
+
|
29
38
|
@value = der[0, total_length]
|
39
|
+
|
30
40
|
total_length
|
31
41
|
end
|
32
42
|
|
33
43
|
def inspect(level=0)
|
34
|
-
|
35
|
-
str
|
44
|
+
lvl = level >= 0 ? level : 0
|
45
|
+
str = ' ' * lvl
|
36
46
|
str << "#{@name} " unless @name.nil?
|
37
|
-
if @value.nil?
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
47
|
+
str << if @value.nil?
|
48
|
+
'(ANY) NULL'
|
49
|
+
elsif @value.is_a?(OctetString) || @value.is_a?(BitString)
|
50
|
+
"(ANY) #{@value.type}: #{value.value.inspect}"
|
51
|
+
elsif @value.class < Base
|
52
|
+
"(ANY) #{@value.type}: #{value.value}"
|
53
|
+
else
|
54
|
+
"ANY: #{value.to_s.inspect}"
|
55
|
+
end
|
46
56
|
end
|
47
57
|
end
|
48
58
|
end
|
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
|
@@ -44,16 +45,20 @@ module RASN1
|
|
44
45
|
# ctype_implicit = RASN1::Types::Integer.new(implicit: 0)
|
45
46
|
# @author Sylvain Daubert
|
46
47
|
class Base
|
47
|
-
# Allowed ASN.1
|
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
|
@@ -70,13 +75,14 @@ module RASN1
|
|
70
75
|
# Get ASN.1 type
|
71
76
|
# @return [String]
|
72
77
|
def self.type
|
73
|
-
return @type if @type
|
78
|
+
return @type if defined? @type
|
79
|
+
|
74
80
|
@type = self.to_s.gsub(/.*::/, '').gsub(/([a-z0-9])([A-Z])/, '\1 \2').upcase
|
75
81
|
end
|
76
82
|
|
77
83
|
# Get ASN.1 type used to encode this one
|
78
84
|
# @return [String]
|
79
|
-
def self.
|
85
|
+
def self.encoded_type
|
80
86
|
type
|
81
87
|
end
|
82
88
|
|
@@ -91,14 +97,13 @@ module RASN1
|
|
91
97
|
obj
|
92
98
|
end
|
93
99
|
|
94
|
-
|
95
100
|
# @overload initialize(options={})
|
96
101
|
# @param [Hash] options
|
97
|
-
# @option options [Symbol] :class ASN.1
|
102
|
+
# @option options [Symbol] :class ASN.1 class. Default value is +:universal+.
|
98
103
|
# If +:explicit+ or +:implicit:+ is defined, default value is +:context+.
|
99
104
|
# @option options [::Boolean] :optional define this tag as optional. Default
|
100
105
|
# is +false+
|
101
|
-
# @option options [Object] :default default value
|
106
|
+
# @option options [Object] :default default value (ASN.1 DEFAULT)
|
102
107
|
# @option options [Object] :value value to set
|
103
108
|
# @option options [::Integer] :implicit define an IMPLICIT tagged type
|
104
109
|
# @option options [::Integer] :explicit define an EXPLICIT tagged type
|
@@ -108,11 +113,11 @@ module RASN1
|
|
108
113
|
# @overload initialize(value, options={})
|
109
114
|
# @param [Object] value value to set for this ASN.1 object
|
110
115
|
# @param [Hash] options
|
111
|
-
# @option options [Symbol] :class ASN.1
|
116
|
+
# @option options [Symbol] :class ASN.1 class. Default value is +:universal+.
|
112
117
|
# If +:explicit+ or +:implicit:+ is defined, default value is +:context+.
|
113
|
-
# @option options [::Boolean] :optional define this
|
118
|
+
# @option options [::Boolean] :optional define this value as optional. Default
|
114
119
|
# is +false+
|
115
|
-
# @option options [Object] :default default value
|
120
|
+
# @option options [Object] :default default value (ASN.1 DEFAULT)
|
116
121
|
# @option options [::Integer] :implicit define an IMPLICIT tagged type
|
117
122
|
# @option options [::Integer] :explicit define an EXPLICIT tagged type
|
118
123
|
# @option options [::Boolean] :constructed if +true+, set type as constructed.
|
@@ -128,20 +133,10 @@ module RASN1
|
|
128
133
|
end
|
129
134
|
end
|
130
135
|
|
131
|
-
# Used by +#dup+ and +#clone+. Deep copy @value.
|
132
|
-
def initialize_copy(
|
133
|
-
@value =
|
134
|
-
|
135
|
-
@value
|
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
|
136
|
+
# Used by +#dup+ and +#clone+. Deep copy @value and @default.
|
137
|
+
def initialize_copy(_other)
|
138
|
+
@value = @value.dup
|
139
|
+
@default = @default.dup
|
145
140
|
end
|
146
141
|
|
147
142
|
# Get value or default value
|
@@ -168,21 +163,21 @@ module RASN1
|
|
168
163
|
# @return [::Boolean,nil] return +nil+ if not tagged, return +true+
|
169
164
|
# if explicit, else +false+
|
170
165
|
def explicit?
|
171
|
-
@tag
|
166
|
+
!defined?(@tag) ? nil : @tag == :explicit
|
172
167
|
end
|
173
168
|
|
174
169
|
# Say if a tagged type is implicit
|
175
170
|
# @return [::Boolean,nil] return +nil+ if not tagged, return +true+
|
176
171
|
# if implicit, else +false+
|
177
172
|
def implicit?
|
178
|
-
@tag
|
173
|
+
!defined?(@tag) ? nil : @tag == :implicit
|
179
174
|
end
|
180
175
|
|
181
176
|
# @abstract This method SHOULD be partly implemented by subclasses, which
|
182
177
|
# SHOULD respond to +#value_to_der+.
|
183
178
|
# @return [String] DER-formated string
|
184
179
|
def to_der
|
185
|
-
|
180
|
+
build
|
186
181
|
end
|
187
182
|
|
188
183
|
# @return [::Boolean] +true+ if this is a primitive type
|
@@ -192,7 +187,7 @@ module RASN1
|
|
192
187
|
|
193
188
|
# @return [::Boolean] +true+ if this is a constructed type
|
194
189
|
def constructed?
|
195
|
-
|
190
|
+
(self.class < Constructed) || !!@constructed
|
196
191
|
end
|
197
192
|
|
198
193
|
# Get ASN.1 type
|
@@ -201,17 +196,10 @@ module RASN1
|
|
201
196
|
self.class.type
|
202
197
|
end
|
203
198
|
|
204
|
-
# Get
|
199
|
+
# Get identifier value
|
205
200
|
# @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 || self.class::TAG) | CLASSES[@asn1_class] | pc
|
201
|
+
def id
|
202
|
+
id_value
|
215
203
|
end
|
216
204
|
|
217
205
|
# @abstract This method SHOULD be partly implemented by subclasses to parse
|
@@ -222,11 +210,13 @@ module RASN1
|
|
222
210
|
# @return [Integer] total number of parsed bytes
|
223
211
|
# @raise [ASN1Error] error on parsing
|
224
212
|
def parse!(der, ber: false)
|
225
|
-
return 0 unless
|
213
|
+
return 0 unless check_id(der)
|
226
214
|
|
227
|
-
|
215
|
+
id_size = Types.decode_identifier_octets(der).last
|
216
|
+
total_length, data = get_data(der[id_size..-1], ber)
|
217
|
+
total_length += id_size
|
228
218
|
if explicit?
|
229
|
-
# Delegate to #explicit type to generate sub-
|
219
|
+
# Delegate to #explicit type to generate sub-value
|
230
220
|
type = explicit_type
|
231
221
|
type.value = @value
|
232
222
|
type.parse!(data)
|
@@ -247,11 +237,9 @@ module RASN1
|
|
247
237
|
# @param [Integer] level
|
248
238
|
# @return [String]
|
249
239
|
def inspect(level=0)
|
250
|
-
str =
|
251
|
-
str <<
|
252
|
-
str <<
|
253
|
-
str << "#{type}: #{value.inspect}"
|
254
|
-
str << " OPTIONAL" if optional?
|
240
|
+
str = common_inspect(level)
|
241
|
+
str << " #{value.inspect}"
|
242
|
+
str << ' OPTIONAL' if optional?
|
255
243
|
str << " DEFAULT #{@default}" unless @default.nil?
|
256
244
|
str
|
257
245
|
end
|
@@ -265,6 +253,23 @@ module RASN1
|
|
265
253
|
|
266
254
|
private
|
267
255
|
|
256
|
+
def pc_bit
|
257
|
+
if @constructed.nil?
|
258
|
+
self.class::ASN1_PC
|
259
|
+
elsif @constructed # true
|
260
|
+
Constructed::ASN1_PC
|
261
|
+
else # false
|
262
|
+
Primitive::ASN1_PC
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def common_inspect(level)
|
267
|
+
lvl = level >= 0 ? level : 0
|
268
|
+
str = ' ' * lvl
|
269
|
+
str << "#{@name} " unless @name.nil?
|
270
|
+
str << "#{type}:"
|
271
|
+
end
|
272
|
+
|
268
273
|
def value_to_der
|
269
274
|
case @value
|
270
275
|
when Base
|
@@ -274,7 +279,7 @@ module RASN1
|
|
274
279
|
end
|
275
280
|
end
|
276
281
|
|
277
|
-
def der_to_value(der, ber:false)
|
282
|
+
def der_to_value(der, ber: false)
|
278
283
|
@value = der
|
279
284
|
end
|
280
285
|
|
@@ -285,6 +290,7 @@ module RASN1
|
|
285
290
|
set_tag options
|
286
291
|
@value = options[:value]
|
287
292
|
@name = options[:name]
|
293
|
+
@options = options
|
288
294
|
end
|
289
295
|
|
290
296
|
def set_class(asn1_class)
|
@@ -292,11 +298,9 @@ module RASN1
|
|
292
298
|
when nil
|
293
299
|
@asn1_class = :universal
|
294
300
|
when Symbol
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
raise ClassError
|
299
|
-
end
|
301
|
+
raise ClassError unless CLASSES.key? asn1_class
|
302
|
+
|
303
|
+
@asn1_class = asn1_class
|
300
304
|
else
|
301
305
|
raise ClassError
|
302
306
|
end
|
@@ -315,27 +319,27 @@ module RASN1
|
|
315
319
|
def set_tag(options)
|
316
320
|
if options[:explicit]
|
317
321
|
@tag = :explicit
|
318
|
-
@
|
322
|
+
@id_value = options[:explicit]
|
319
323
|
@constructed = options[:constructed]
|
320
324
|
elsif options[:implicit]
|
321
325
|
@tag = :implicit
|
322
|
-
@
|
326
|
+
@id_value = options[:implicit]
|
323
327
|
@constructed = options[:constructed]
|
324
328
|
elsif options[:tag_value]
|
325
|
-
@
|
329
|
+
@id_value = options[:tag_value]
|
326
330
|
@constructed = options[:constructed]
|
327
331
|
end
|
328
332
|
|
329
|
-
@asn1_class = :context if @tag
|
333
|
+
@asn1_class = :context if defined?(@tag) && (@asn1_class == :universal)
|
330
334
|
end
|
331
335
|
|
332
|
-
def
|
333
|
-
!(!@default.nil?
|
334
|
-
!(optional?
|
336
|
+
def can_build?
|
337
|
+
!(!@default.nil? && (@value.nil? || (@value == @default))) &&
|
338
|
+
!(optional? && @value.nil?)
|
335
339
|
end
|
336
340
|
|
337
|
-
def
|
338
|
-
if
|
341
|
+
def build
|
342
|
+
if can_build?
|
339
343
|
if explicit?
|
340
344
|
v = explicit_type
|
341
345
|
v.value = @value
|
@@ -343,29 +347,52 @@ module RASN1
|
|
343
347
|
else
|
344
348
|
encoded_value = value_to_der
|
345
349
|
end
|
346
|
-
|
350
|
+
encode_identifier_octets << encode_size(encoded_value.size) << encoded_value
|
347
351
|
else
|
348
352
|
''
|
349
353
|
end
|
350
354
|
end
|
351
355
|
|
352
|
-
def
|
353
|
-
|
354
|
-
|
356
|
+
def id_value
|
357
|
+
return @id_value if defined? @id_value
|
358
|
+
|
359
|
+
self.class::ID
|
360
|
+
end
|
361
|
+
|
362
|
+
def encode_identifier_octets
|
363
|
+
id2octets.pack('C*')
|
364
|
+
end
|
365
|
+
|
366
|
+
def id2octets
|
367
|
+
first_octet = CLASSES[asn1_class] | pc_bit
|
368
|
+
if id < MULTI_OCTETS_ID
|
369
|
+
[first_octet | id]
|
355
370
|
else
|
356
|
-
|
371
|
+
[first_octet | MULTI_OCTETS_ID] + unsigned_to_chained_octets(id)
|
357
372
|
end
|
358
373
|
end
|
359
374
|
|
375
|
+
# Encode an unsigned integer on multiple octets.
|
376
|
+
# Value is encoded on bit 6-0 of each octet, bit 7(MSB) indicates wether
|
377
|
+
# further octets follow.
|
378
|
+
def unsigned_to_chained_octets(value)
|
379
|
+
ary = []
|
380
|
+
while value.positive?
|
381
|
+
ary.unshift(value & 0x7f | 0x80)
|
382
|
+
value >>= 7
|
383
|
+
end
|
384
|
+
ary[-1] &= 0x7f
|
385
|
+
ary
|
386
|
+
end
|
387
|
+
|
360
388
|
def encode_size(size)
|
361
389
|
if size >= INDEFINITE_LENGTH
|
362
390
|
bytes = []
|
363
391
|
while size > 255
|
364
|
-
bytes
|
392
|
+
bytes.unshift(size & 0xff)
|
365
393
|
size >>= 8
|
366
394
|
end
|
367
|
-
bytes
|
368
|
-
bytes.reverse!
|
395
|
+
bytes.unshift(size)
|
369
396
|
bytes.unshift(INDEFINITE_LENGTH | bytes.size)
|
370
397
|
bytes.pack('C*')
|
371
398
|
else
|
@@ -373,15 +400,16 @@ module RASN1
|
|
373
400
|
end
|
374
401
|
end
|
375
402
|
|
376
|
-
def
|
377
|
-
|
378
|
-
|
403
|
+
def check_id(der)
|
404
|
+
expected_id = encode_identifier_octets
|
405
|
+
real_id = der[0, expected_id.size]
|
406
|
+
if real_id != expected_id
|
379
407
|
if optional?
|
380
408
|
@value = nil
|
381
409
|
elsif !@default.nil?
|
382
410
|
@value = @default
|
383
411
|
else
|
384
|
-
|
412
|
+
raise_id_error(der)
|
385
413
|
end
|
386
414
|
false
|
387
415
|
else
|
@@ -390,33 +418,29 @@ module RASN1
|
|
390
418
|
end
|
391
419
|
|
392
420
|
def get_data(der, ber)
|
393
|
-
length = der[
|
421
|
+
length = der[0, 1].unpack1('C')
|
394
422
|
length_length = 0
|
395
423
|
|
396
424
|
if length == INDEFINITE_LENGTH
|
397
425
|
if primitive?
|
398
|
-
raise ASN1Error, "malformed #{type}
|
399
|
-
|
426
|
+
raise ASN1Error, "malformed #{type}: indefinite length " \
|
427
|
+
'forbidden for primitive types'
|
428
|
+
elsif ber
|
429
|
+
raise NotImplementedError, 'indefinite length not supported'
|
400
430
|
else
|
401
|
-
|
402
|
-
raise NotImplementedError, "TAG: indefinite length not " \
|
403
|
-
"supported yet"
|
404
|
-
else
|
405
|
-
raise ASN1Error, "TAG: indefinite length forbidden in DER " \
|
406
|
-
"encoding"
|
407
|
-
end
|
431
|
+
raise ASN1Error, 'indefinite length forbidden in DER encoding'
|
408
432
|
end
|
409
433
|
elsif length < INDEFINITE_LENGTH
|
410
|
-
data = der[
|
434
|
+
data = der[1, length]
|
411
435
|
else
|
412
436
|
length_length = length & 0x7f
|
413
|
-
length = der[
|
414
|
-
|
415
|
-
data = der[
|
437
|
+
length = der[1, length_length].unpack('C*')
|
438
|
+
.reduce(0) { |len, b| (len << 8) | b }
|
439
|
+
data = der[1 + length_length, length]
|
416
440
|
end
|
417
441
|
|
418
|
-
total_length =
|
419
|
-
total_length += length_length if length_length
|
442
|
+
total_length = 1 + length
|
443
|
+
total_length += length_length if length_length.positive?
|
420
444
|
|
421
445
|
[total_length, data]
|
422
446
|
end
|
@@ -425,31 +449,38 @@ module RASN1
|
|
425
449
|
self.class.new
|
426
450
|
end
|
427
451
|
|
428
|
-
def
|
429
|
-
msg =
|
452
|
+
def raise_id_error(der)
|
453
|
+
msg = name.nil? ? +'' : +"#{name}: "
|
454
|
+
msg << "Expected #{self2name} but get #{der2name(der)}"
|
430
455
|
raise ASN1Error, msg
|
431
456
|
end
|
432
457
|
|
458
|
+
def class_from_numeric_id(id)
|
459
|
+
CLASSES.key(id & CLASS_MASK)
|
460
|
+
end
|
461
|
+
|
433
462
|
def self2name
|
434
|
-
name =
|
435
|
-
name << " #{tag & Constructed::ASN1_PC > 0 ? 'CONSTRUCTED' : 'PRIMITIVE'}"
|
463
|
+
name = +"#{asn1_class.to_s.upcase} #{constructed? ? 'CONSTRUCTED' : 'PRIMITIVE'}"
|
436
464
|
if implicit? || explicit?
|
437
|
-
name << ' 0x%
|
465
|
+
name << ' 0x%X (0x%s)' % [id, bin2hex(encode_identifier_octets)]
|
438
466
|
else
|
439
467
|
name << ' ' << self.class.type
|
440
468
|
end
|
441
469
|
end
|
442
470
|
|
443
|
-
def
|
444
|
-
return 'no
|
471
|
+
def der2name(der)
|
472
|
+
return 'no ID' if der.nil? || der.empty?
|
473
|
+
|
474
|
+
asn1_class, pc, id, id_size = Types.decode_identifier_octets(der)
|
475
|
+
name = +"#{asn1_class.to_s.upcase} #{pc.to_s.upcase}"
|
476
|
+
type = Types.constants.map { |c| Types.const_get(c) }
|
477
|
+
.select { |klass| klass < Primitive || klass < Constructed }
|
478
|
+
.find { |klass| klass::ID == id }
|
479
|
+
name << " #{type.nil? ? '0x%X (0x%s)' % [id, bin2hex(der[0...id_size])] : type.encoded_type}"
|
480
|
+
end
|
445
481
|
|
446
|
-
|
447
|
-
|
448
|
-
name << " #{itag & Constructed::ASN1_PC > 0 ? 'CONSTRUCTED' : 'PRIMITIVE'}"
|
449
|
-
type = Types.constants.map { |c| Types.const_get(c) }.
|
450
|
-
select { |klass| klass < Primitive || klass < Constructed }.
|
451
|
-
find { |klass| klass::TAG == itag & 0x1f }
|
452
|
-
name << " #{type.nil? ? "0x%02X" % (itag & 0x1f) : type.encode_type }"
|
482
|
+
def bin2hex(str)
|
483
|
+
str.unpack1('H*')
|
453
484
|
end
|
454
485
|
end
|
455
486
|
end
|