rasn1 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|