rasn1 0.7.1 → 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/lib/rasn1.rb +1 -1
- data/lib/rasn1/model.rb +25 -28
- data/lib/rasn1/types.rb +41 -15
- data/lib/rasn1/types/any.rb +5 -1
- data/lib/rasn1/types/base.rb +102 -85
- data/lib/rasn1/types/bit_string.rb +9 -11
- data/lib/rasn1/types/boolean.rb +3 -3
- data/lib/rasn1/types/choice.rb +1 -1
- data/lib/rasn1/types/constructed.rb +2 -1
- data/lib/rasn1/types/enumerated.rb +2 -2
- data/lib/rasn1/types/generalized_time.rb +2 -2
- data/lib/rasn1/types/ia5string.rb +2 -2
- data/lib/rasn1/types/integer.rb +26 -41
- data/lib/rasn1/types/null.rb +3 -3
- data/lib/rasn1/types/numeric_string.rb +4 -6
- data/lib/rasn1/types/object_id.rb +15 -46
- data/lib/rasn1/types/octet_string.rb +2 -2
- data/lib/rasn1/types/printable_string.rb +5 -6
- data/lib/rasn1/types/sequence.rb +2 -2
- data/lib/rasn1/types/sequence_of.rb +3 -3
- data/lib/rasn1/types/set.rb +2 -2
- data/lib/rasn1/types/set_of.rb +2 -2
- data/lib/rasn1/types/utc_time.rb +2 -2
- data/lib/rasn1/types/utf8_string.rb +2 -2
- data/lib/rasn1/types/visible_string.rb +2 -2
- data/lib/rasn1/version.rb +1 -1
- metadata +26 -56
- data/.gitignore +0 -11
- data/.rubocop.yml +0 -32
- data/.travis.yml +0 -11
- data/Changelog.md +0 -15
- data/Gemfile +0 -4
- data/Rakefile +0 -12
- data/rasn1.gemspec +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4eb9957878c25e54a394fee02aab5a42aa1201ad6250f7f6a2a3992128c87d6
|
4
|
+
data.tar.gz: 3b3d3c85d619ee7f78923d7f7c839874f329087b0b1a4094839b059daf94c2ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9eb501aacf629355e56a4103dfc3e354bfa035c031a23f2dcc61f8add191a13960cd64ea68db36340694f3b20aba316c0088ebe91943d795405b11489be9342e
|
7
|
+
data.tar.gz: 115cef9248e5251a24ec0bb6d6e977084cfb4ff78118a7f5be31ee8fea05a0c831b935fa72c18bdc08e71bb729a85cff2b394f4a84aafd56245f70908f0a4dc6
|
data/lib/rasn1.rb
CHANGED
data/lib/rasn1/model.rb
CHANGED
@@ -204,7 +204,7 @@ module RASN1
|
|
204
204
|
# +Object#object_id+.
|
205
205
|
# @see Types::ObjectId#initialize
|
206
206
|
def objectid(name, options={})
|
207
|
-
options
|
207
|
+
options[:name] = name
|
208
208
|
proc = proc { |opts| Types::ObjectId.new(options.merge(opts)) }
|
209
209
|
@root = [name, proc]
|
210
210
|
end
|
@@ -213,7 +213,7 @@ module RASN1
|
|
213
213
|
# @param [Hash] options
|
214
214
|
# @see Types::Any#initialize
|
215
215
|
def any(name, options={})
|
216
|
-
options
|
216
|
+
options[:name] = name
|
217
217
|
proc = proc { |opts| Types::Any.new(options.merge(opts)) }
|
218
218
|
@root = [name, proc]
|
219
219
|
end
|
@@ -369,7 +369,7 @@ module RASN1
|
|
369
369
|
elt = self[name]
|
370
370
|
return elt unless elt.nil?
|
371
371
|
|
372
|
-
|
372
|
+
@elements.each_key do |subelt_name|
|
373
373
|
if self[subelt_name].is_a?(Model)
|
374
374
|
elt = self[subelt_name][name]
|
375
375
|
return elt unless elt.nil?
|
@@ -408,40 +408,37 @@ module RASN1
|
|
408
408
|
@elements[name].value = content.map do |name2, proc_or_class, content2|
|
409
409
|
subel = get_type(proc_or_class)
|
410
410
|
@elements[name2] = subel
|
411
|
-
if composed?(subel) && content2.is_a?(Array)
|
412
|
-
set_elements(name2, proc_or_class, content2)
|
413
|
-
end
|
411
|
+
set_elements(name2, proc_or_class, content2) if composed?(subel) && content2.is_a?(Array)
|
414
412
|
subel
|
415
413
|
end
|
416
414
|
end
|
417
415
|
|
418
416
|
def initialize_elements(obj, args)
|
419
417
|
args.each do |name, value|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
end
|
437
|
-
else
|
438
|
-
value.each do |el|
|
439
|
-
obj[name] << el
|
440
|
-
end
|
418
|
+
next unless obj[name]
|
419
|
+
|
420
|
+
case value
|
421
|
+
when Hash
|
422
|
+
raise ArgumentError, "element #{name}: may only pass a Hash for Model elements" unless obj[name].is_a? Model
|
423
|
+
|
424
|
+
initialize_elements obj[name], value
|
425
|
+
when Array
|
426
|
+
composed = if obj[name].is_a? Model
|
427
|
+
obj[name].root
|
428
|
+
else
|
429
|
+
obj[name]
|
430
|
+
end
|
431
|
+
if composed.of_type.is_a? Model
|
432
|
+
value.each do |el|
|
433
|
+
composed << initialize_elements(composed.of_type.class.new, el)
|
441
434
|
end
|
442
435
|
else
|
443
|
-
|
436
|
+
value.each do |el|
|
437
|
+
obj[name] << el
|
438
|
+
end
|
444
439
|
end
|
440
|
+
else
|
441
|
+
obj[name].value = value
|
445
442
|
end
|
446
443
|
end
|
447
444
|
end
|
data/lib/rasn1/types.rb
CHANGED
@@ -18,32 +18,58 @@ module RASN1
|
|
18
18
|
.select { |klass| klass < Constructed }
|
19
19
|
end
|
20
20
|
|
21
|
-
#
|
21
|
+
# @private
|
22
|
+
# Decode a DER string to extract identifier octets.
|
23
|
+
# @param [String] der
|
24
|
+
# @return [Array] Return ASN.1 class as Symbol, contructed/primitive as Symbol,
|
25
|
+
# ID and size of identifier octets
|
26
|
+
def self.decode_identifier_octets(der)
|
27
|
+
first_octet = der[0].unpack1('C')
|
28
|
+
asn1_class = Types::Base::CLASSES.key(first_octet & Types::Base::CLASS_MASK)
|
29
|
+
pc = (first_octet & Types::Constructed::ASN1_PC).positive? ? :constructed : :primitive
|
30
|
+
id = first_octet & Types::Base::MULTI_OCTETS_ID
|
31
|
+
|
32
|
+
size = if id == Types::Base::MULTI_OCTETS_ID
|
33
|
+
id = 0
|
34
|
+
1.upto(der.size - 1) do |i|
|
35
|
+
octet = der[i].unpack1('C')
|
36
|
+
id = (id << 7) | (octet & 0x7f)
|
37
|
+
break i + 1 if (octet & 0x80).zero?
|
38
|
+
end
|
39
|
+
else
|
40
|
+
1
|
41
|
+
end
|
42
|
+
|
43
|
+
[asn1_class, pc, id, size]
|
44
|
+
end
|
45
|
+
|
46
|
+
# Give ASN.1 type from a DER string. If ID is unknown, return a {Types::Base}
|
22
47
|
# object.
|
23
|
-
# @param [
|
48
|
+
# @param [String] der
|
24
49
|
# @return [Types::Base]
|
25
50
|
# @raise [ASN1Error] +tag+ is out of range
|
26
|
-
def self.
|
27
|
-
|
28
|
-
|
29
|
-
unless defined? @tag2types
|
51
|
+
def self.id2type(der)
|
52
|
+
# Define a cache for well-known ASN.1 types
|
53
|
+
unless defined? @id2types
|
30
54
|
constructed = self.constructed - [Types::SequenceOf, Types::SetOf]
|
31
55
|
primitives = self.primitives - [Types::Enumerated]
|
32
56
|
ary = (primitives + constructed).map do |type|
|
33
|
-
next unless type.const_defined? :
|
57
|
+
next unless type.const_defined? :ID
|
34
58
|
|
35
|
-
[type::
|
59
|
+
[type::ID, type]
|
36
60
|
end
|
37
|
-
@
|
38
|
-
@
|
39
|
-
@
|
61
|
+
@id2types = Hash[ary]
|
62
|
+
@id2types.default = Types::Base
|
63
|
+
@id2types.freeze
|
40
64
|
end
|
41
65
|
|
42
|
-
|
43
|
-
|
44
|
-
|
66
|
+
asn1class, pc, id, = self.decode_identifier_octets(der)
|
67
|
+
# cache_id: check versus class and 5 LSB bits
|
68
|
+
cache_id = der.unpack1('C') & 0xdf
|
69
|
+
klass = cache_id < Types::Base::MULTI_OCTETS_ID ? @id2types[id] : Types::Base
|
70
|
+
is_constructed = (pc == :constructed)
|
45
71
|
options = { class: asn1class, constructed: is_constructed }
|
46
|
-
options[:tag_value] =
|
72
|
+
options[:tag_value] = id if klass == Types::Base
|
47
73
|
klass.new(options)
|
48
74
|
end
|
49
75
|
end
|
data/lib/rasn1/types/any.rb
CHANGED
@@ -31,8 +31,12 @@ module RASN1
|
|
31
31
|
raise ASN1Error, 'Expected ANY but get nothing'
|
32
32
|
end
|
33
33
|
|
34
|
-
|
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
|
+
|
35
38
|
@value = der[0, total_length]
|
39
|
+
|
36
40
|
total_length
|
37
41
|
end
|
38
42
|
|
data/lib/rasn1/types/base.rb
CHANGED
@@ -5,7 +5,7 @@ module RASN1
|
|
5
5
|
# @abstract This is base class for all ASN.1 types.
|
6
6
|
#
|
7
7
|
# Subclasses SHOULD define:
|
8
|
-
# *
|
8
|
+
# * an ID constant defining ASN.1 BER/DER identification number,
|
9
9
|
# * a private method {#value_to_der} converting its {#value} to DER,
|
10
10
|
# * a private method {#der_to_value} converting DER into {#value}.
|
11
11
|
#
|
@@ -13,15 +13,15 @@ module RASN1
|
|
13
13
|
# An optional value may be defined using +:optional+ key from {#initialize}:
|
14
14
|
# Integer.new(:int, optional: true)
|
15
15
|
# An optional value implies:
|
16
|
-
# * while parsing, if decoded
|
17
|
-
# 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,
|
18
18
|
# * while encoding, if {#value} is +nil+, this value is not encoded.
|
19
19
|
# ==Define a default value
|
20
20
|
# A default value may be defined using +:default+ key from {#initialize}:
|
21
21
|
# Integer.new(:int, default: 0)
|
22
22
|
# A default value implies:
|
23
|
-
# * while parsing, if decoded
|
24
|
-
# 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,
|
25
25
|
# * while encoding, if {#value} is equal to default value, this value is not
|
26
26
|
# encoded.
|
27
27
|
# ==Define a tagged value
|
@@ -45,30 +45,20 @@ module RASN1
|
|
45
45
|
# ctype_implicit = RASN1::Types::Integer.new(implicit: 0)
|
46
46
|
# @author Sylvain Daubert
|
47
47
|
class Base
|
48
|
-
# Allowed ASN.1
|
48
|
+
# Allowed ASN.1 classes
|
49
49
|
CLASSES = {
|
50
|
-
universal:
|
50
|
+
universal: 0x00,
|
51
51
|
application: 0x40,
|
52
|
-
context:
|
53
|
-
private:
|
52
|
+
context: 0x80,
|
53
|
+
private: 0xc0
|
54
54
|
}.freeze
|
55
55
|
|
56
|
-
# @private Types that cannot be dupped (Ruby <= 2.3)
|
57
|
-
UNDUPPABLE_TYPES = [[NilClass, nil], [TrueClass, true], [FalseClass, false], [Integer, 0]].map do |klass, obj|
|
58
|
-
begin
|
59
|
-
obj.dup
|
60
|
-
nil
|
61
|
-
rescue => TypeError
|
62
|
-
klass
|
63
|
-
end
|
64
|
-
end.compact.freeze
|
65
|
-
|
66
56
|
# Binary mask to get class
|
67
57
|
# @private
|
68
58
|
CLASS_MASK = 0xc0
|
69
59
|
|
70
|
-
#
|
71
|
-
|
60
|
+
# @private first octet identifier for multi-octets identifier
|
61
|
+
MULTI_OCTETS_ID = 0x1f
|
72
62
|
|
73
63
|
# Length value for indefinite length
|
74
64
|
INDEFINITE_LENGTH = 0x80
|
@@ -92,7 +82,7 @@ module RASN1
|
|
92
82
|
|
93
83
|
# Get ASN.1 type used to encode this one
|
94
84
|
# @return [String]
|
95
|
-
def self.
|
85
|
+
def self.encoded_type
|
96
86
|
type
|
97
87
|
end
|
98
88
|
|
@@ -109,11 +99,11 @@ module RASN1
|
|
109
99
|
|
110
100
|
# @overload initialize(options={})
|
111
101
|
# @param [Hash] options
|
112
|
-
# @option options [Symbol] :class ASN.1
|
102
|
+
# @option options [Symbol] :class ASN.1 class. Default value is +:universal+.
|
113
103
|
# If +:explicit+ or +:implicit:+ is defined, default value is +:context+.
|
114
104
|
# @option options [::Boolean] :optional define this tag as optional. Default
|
115
105
|
# is +false+
|
116
|
-
# @option options [Object] :default default value
|
106
|
+
# @option options [Object] :default default value (ASN.1 DEFAULT)
|
117
107
|
# @option options [Object] :value value to set
|
118
108
|
# @option options [::Integer] :implicit define an IMPLICIT tagged type
|
119
109
|
# @option options [::Integer] :explicit define an EXPLICIT tagged type
|
@@ -123,11 +113,11 @@ module RASN1
|
|
123
113
|
# @overload initialize(value, options={})
|
124
114
|
# @param [Object] value value to set for this ASN.1 object
|
125
115
|
# @param [Hash] options
|
126
|
-
# @option options [Symbol] :class ASN.1
|
116
|
+
# @option options [Symbol] :class ASN.1 class. Default value is +:universal+.
|
127
117
|
# If +:explicit+ or +:implicit:+ is defined, default value is +:context+.
|
128
|
-
# @option options [::Boolean] :optional define this
|
118
|
+
# @option options [::Boolean] :optional define this value as optional. Default
|
129
119
|
# is +false+
|
130
|
-
# @option options [Object] :default default value
|
120
|
+
# @option options [Object] :default default value (ASN.1 DEFAULT)
|
131
121
|
# @option options [::Integer] :implicit define an IMPLICIT tagged type
|
132
122
|
# @option options [::Integer] :explicit define an EXPLICIT tagged type
|
133
123
|
# @option options [::Boolean] :constructed if +true+, set type as constructed.
|
@@ -145,8 +135,8 @@ module RASN1
|
|
145
135
|
|
146
136
|
# Used by +#dup+ and +#clone+. Deep copy @value and @default.
|
147
137
|
def initialize_copy(_other)
|
148
|
-
@value = @value.dup
|
149
|
-
@default = @default.dup
|
138
|
+
@value = @value.dup
|
139
|
+
@default = @default.dup
|
150
140
|
end
|
151
141
|
|
152
142
|
# Get value or default value
|
@@ -187,7 +177,7 @@ module RASN1
|
|
187
177
|
# SHOULD respond to +#value_to_der+.
|
188
178
|
# @return [String] DER-formated string
|
189
179
|
def to_der
|
190
|
-
|
180
|
+
build
|
191
181
|
end
|
192
182
|
|
193
183
|
# @return [::Boolean] +true+ if this is a primitive type
|
@@ -206,17 +196,10 @@ module RASN1
|
|
206
196
|
self.class.type
|
207
197
|
end
|
208
198
|
|
209
|
-
# Get
|
199
|
+
# Get identifier value
|
210
200
|
# @return [Integer]
|
211
|
-
def
|
212
|
-
|
213
|
-
self.class::ASN1_PC
|
214
|
-
elsif @constructed # true
|
215
|
-
Constructed::ASN1_PC
|
216
|
-
else # false
|
217
|
-
0
|
218
|
-
end
|
219
|
-
tag_value | CLASSES[@asn1_class] | pc
|
201
|
+
def id
|
202
|
+
id_value
|
220
203
|
end
|
221
204
|
|
222
205
|
# @abstract This method SHOULD be partly implemented by subclasses to parse
|
@@ -227,11 +210,13 @@ module RASN1
|
|
227
210
|
# @return [Integer] total number of parsed bytes
|
228
211
|
# @raise [ASN1Error] error on parsing
|
229
212
|
def parse!(der, ber: false)
|
230
|
-
return 0 unless
|
213
|
+
return 0 unless check_id(der)
|
231
214
|
|
232
|
-
|
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
|
233
218
|
if explicit?
|
234
|
-
# Delegate to #explicit type to generate sub-
|
219
|
+
# Delegate to #explicit type to generate sub-value
|
235
220
|
type = explicit_type
|
236
221
|
type.value = @value
|
237
222
|
type.parse!(data)
|
@@ -268,6 +253,16 @@ module RASN1
|
|
268
253
|
|
269
254
|
private
|
270
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
|
+
|
271
266
|
def common_inspect(level)
|
272
267
|
lvl = level >= 0 ? level : 0
|
273
268
|
str = ' ' * lvl
|
@@ -295,6 +290,7 @@ module RASN1
|
|
295
290
|
set_tag options
|
296
291
|
@value = options[:value]
|
297
292
|
@name = options[:name]
|
293
|
+
@options = options
|
298
294
|
end
|
299
295
|
|
300
296
|
def set_class(asn1_class)
|
@@ -302,7 +298,7 @@ module RASN1
|
|
302
298
|
when nil
|
303
299
|
@asn1_class = :universal
|
304
300
|
when Symbol
|
305
|
-
raise ClassError unless CLASSES.
|
301
|
+
raise ClassError unless CLASSES.key? asn1_class
|
306
302
|
|
307
303
|
@asn1_class = asn1_class
|
308
304
|
else
|
@@ -323,27 +319,27 @@ module RASN1
|
|
323
319
|
def set_tag(options)
|
324
320
|
if options[:explicit]
|
325
321
|
@tag = :explicit
|
326
|
-
@
|
322
|
+
@id_value = options[:explicit]
|
327
323
|
@constructed = options[:constructed]
|
328
324
|
elsif options[:implicit]
|
329
325
|
@tag = :implicit
|
330
|
-
@
|
326
|
+
@id_value = options[:implicit]
|
331
327
|
@constructed = options[:constructed]
|
332
328
|
elsif options[:tag_value]
|
333
|
-
@
|
329
|
+
@id_value = options[:tag_value]
|
334
330
|
@constructed = options[:constructed]
|
335
331
|
end
|
336
332
|
|
337
333
|
@asn1_class = :context if defined?(@tag) && (@asn1_class == :universal)
|
338
334
|
end
|
339
335
|
|
340
|
-
def
|
336
|
+
def can_build?
|
341
337
|
!(!@default.nil? && (@value.nil? || (@value == @default))) &&
|
342
338
|
!(optional? && @value.nil?)
|
343
339
|
end
|
344
340
|
|
345
|
-
def
|
346
|
-
if
|
341
|
+
def build
|
342
|
+
if can_build?
|
347
343
|
if explicit?
|
348
344
|
v = explicit_type
|
349
345
|
v.value = @value
|
@@ -351,22 +347,42 @@ module RASN1
|
|
351
347
|
else
|
352
348
|
encoded_value = value_to_der
|
353
349
|
end
|
354
|
-
|
350
|
+
encode_identifier_octets << encode_size(encoded_value.size) << encoded_value
|
355
351
|
else
|
356
352
|
''
|
357
353
|
end
|
358
354
|
end
|
359
355
|
|
360
|
-
def
|
361
|
-
return @
|
356
|
+
def id_value
|
357
|
+
return @id_value if defined? @id_value
|
358
|
+
|
359
|
+
self.class::ID
|
360
|
+
end
|
362
361
|
|
363
|
-
|
362
|
+
def encode_identifier_octets
|
363
|
+
id2octets.pack('C*')
|
364
364
|
end
|
365
365
|
|
366
|
-
def
|
367
|
-
|
366
|
+
def id2octets
|
367
|
+
first_octet = CLASSES[asn1_class] | pc_bit
|
368
|
+
if id < MULTI_OCTETS_ID
|
369
|
+
[first_octet | id]
|
370
|
+
else
|
371
|
+
[first_octet | MULTI_OCTETS_ID] + unsigned_to_chained_octets(id)
|
372
|
+
end
|
373
|
+
end
|
368
374
|
|
369
|
-
|
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
|
370
386
|
end
|
371
387
|
|
372
388
|
def encode_size(size)
|
@@ -384,15 +400,16 @@ module RASN1
|
|
384
400
|
end
|
385
401
|
end
|
386
402
|
|
387
|
-
def
|
388
|
-
|
389
|
-
|
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
|
390
407
|
if optional?
|
391
408
|
@value = nil
|
392
409
|
elsif !@default.nil?
|
393
410
|
@value = @default
|
394
411
|
else
|
395
|
-
|
412
|
+
raise_id_error(der)
|
396
413
|
end
|
397
414
|
false
|
398
415
|
else
|
@@ -401,30 +418,28 @@ module RASN1
|
|
401
418
|
end
|
402
419
|
|
403
420
|
def get_data(der, ber)
|
404
|
-
length = der[
|
421
|
+
length = der[0, 1].unpack1('C')
|
405
422
|
length_length = 0
|
406
423
|
|
407
424
|
if length == INDEFINITE_LENGTH
|
408
425
|
if primitive?
|
409
|
-
raise ASN1Error, "malformed #{type}
|
426
|
+
raise ASN1Error, "malformed #{type}: indefinite length " \
|
410
427
|
'forbidden for primitive types'
|
411
428
|
elsif ber
|
412
|
-
raise NotImplementedError, '
|
413
|
-
'supported yet'
|
429
|
+
raise NotImplementedError, 'indefinite length not supported'
|
414
430
|
else
|
415
|
-
raise ASN1Error, '
|
416
|
-
'encoding'
|
431
|
+
raise ASN1Error, 'indefinite length forbidden in DER encoding'
|
417
432
|
end
|
418
433
|
elsif length < INDEFINITE_LENGTH
|
419
|
-
data = der[
|
434
|
+
data = der[1, length]
|
420
435
|
else
|
421
436
|
length_length = length & 0x7f
|
422
|
-
length = der[
|
437
|
+
length = der[1, length_length].unpack('C*')
|
423
438
|
.reduce(0) { |len, b| (len << 8) | b }
|
424
|
-
data = der[
|
439
|
+
data = der[1 + length_length, length]
|
425
440
|
end
|
426
441
|
|
427
|
-
total_length =
|
442
|
+
total_length = 1 + length
|
428
443
|
total_length += length_length if length_length.positive?
|
429
444
|
|
430
445
|
[total_length, data]
|
@@ -434,36 +449,38 @@ module RASN1
|
|
434
449
|
self.class.new
|
435
450
|
end
|
436
451
|
|
437
|
-
def
|
452
|
+
def raise_id_error(der)
|
438
453
|
msg = name.nil? ? +'' : +"#{name}: "
|
439
|
-
msg << "Expected #{self2name} but get #{
|
454
|
+
msg << "Expected #{self2name} but get #{der2name(der)}"
|
440
455
|
raise ASN1Error, msg
|
441
456
|
end
|
442
457
|
|
443
|
-
def
|
444
|
-
CLASSES.key(
|
458
|
+
def class_from_numeric_id(id)
|
459
|
+
CLASSES.key(id & CLASS_MASK)
|
445
460
|
end
|
446
461
|
|
447
462
|
def self2name
|
448
|
-
name =
|
449
|
-
name << " #{(tag & Constructed::ASN1_PC).positive? ? 'CONSTRUCTED' : 'PRIMITIVE'}"
|
463
|
+
name = +"#{asn1_class.to_s.upcase} #{constructed? ? 'CONSTRUCTED' : 'PRIMITIVE'}"
|
450
464
|
if implicit? || explicit?
|
451
|
-
name << ' 0x%
|
465
|
+
name << ' 0x%X (0x%s)' % [id, bin2hex(encode_identifier_octets)]
|
452
466
|
else
|
453
467
|
name << ' ' << self.class.type
|
454
468
|
end
|
455
469
|
end
|
456
470
|
|
457
|
-
def
|
458
|
-
return 'no
|
471
|
+
def der2name(der)
|
472
|
+
return 'no ID' if der.nil? || der.empty?
|
459
473
|
|
460
|
-
|
461
|
-
name =
|
462
|
-
name << " #{(itag & Constructed::ASN1_PC).positive? ? 'CONSTRUCTED' : 'PRIMITIVE'}"
|
474
|
+
asn1_class, pc, id, id_size = Types.decode_identifier_octets(der)
|
475
|
+
name = +"#{asn1_class.to_s.upcase} #{pc.to_s.upcase}"
|
463
476
|
type = Types.constants.map { |c| Types.const_get(c) }
|
464
477
|
.select { |klass| klass < Primitive || klass < Constructed }
|
465
|
-
.find { |klass| klass::
|
466
|
-
name << " #{type.nil? ? '0x%
|
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
|
481
|
+
|
482
|
+
def bin2hex(str)
|
483
|
+
str.unpack1('H*')
|
467
484
|
end
|
468
485
|
end
|
469
486
|
end
|