rasn1 0.5.0 → 0.6.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/.travis.yml +2 -2
- data/lib/rasn1.rb +31 -0
- data/lib/rasn1/model.rb +68 -28
- data/lib/rasn1/types.rb +31 -4
- data/lib/rasn1/types/any.rb +6 -5
- data/lib/rasn1/types/base.rb +80 -36
- data/lib/rasn1/types/bit_string.rb +16 -12
- data/lib/rasn1/types/constructed.rb +4 -1
- data/lib/rasn1/types/enumerated.rb +17 -13
- data/lib/rasn1/types/octet_string.rb +2 -16
- data/lib/rasn1/types/sequence.rb +7 -17
- data/lib/rasn1/types/sequence_of.rb +5 -5
- data/lib/rasn1/types/visible_string.rb +1 -1
- data/lib/rasn1/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 38f025ab48cabca987b7e0813332e9228ab1933a
|
|
4
|
+
data.tar.gz: 84ed306ccd84238b89ea1e02f2b73a9bf8558f41
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a3b4edc322d49eb3e68ecccada5e5022c7f0d08e183a71b991faf62b488c6e70753e531e0a7b5d7bce6bf0a9f4a41da74162f476631097abfd42631962856529
|
|
7
|
+
data.tar.gz: 6144b8db2f536adc0f8d0f61727724b556058fadd14f02666d5f91df8dfd7f0b92a93a2e30c4a51526a61d6997f3b102e8a2b876d2fc74556190e8cf512854cf
|
data/.travis.yml
CHANGED
data/lib/rasn1.rb
CHANGED
|
@@ -29,4 +29,35 @@ module RASN1
|
|
|
29
29
|
"CHOICE #@name: #chosen not set"
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
|
+
|
|
33
|
+
# Parse a DER/BER string without checking a model
|
|
34
|
+
# @note If you want to check ASN.1 grammary, you should define a {Model}
|
|
35
|
+
# and use {Model#parse}.
|
|
36
|
+
# @note This method will never decode SEQUENCE OF or SET OF objects, as these
|
|
37
|
+
# ones use the same encoding as SEQUENCE and SET, respectively.
|
|
38
|
+
# @note Real type of tagged value cannot be guessed. So, such tag will
|
|
39
|
+
# generate {Types::Base} objects.
|
|
40
|
+
# @param [String] der binary string to parse
|
|
41
|
+
# @param [Boolean] ber if +true+, decode a BER string, else a DER one
|
|
42
|
+
# @return [Types::Base]
|
|
43
|
+
def self.parse(der, ber: false)
|
|
44
|
+
root = nil
|
|
45
|
+
while der.size > 0
|
|
46
|
+
type = Types.tag2type(der[0].ord)
|
|
47
|
+
type.parse!(der, ber: ber)
|
|
48
|
+
root = type if root.nil?
|
|
49
|
+
|
|
50
|
+
if [Types::Sequence, Types::Set].include? type.class
|
|
51
|
+
subder = type.value
|
|
52
|
+
ary = []
|
|
53
|
+
while subder.size > 0
|
|
54
|
+
ary << self.parse(subder)
|
|
55
|
+
subder = subder[ary.last.to_der.size..-1]
|
|
56
|
+
end
|
|
57
|
+
type.value = ary
|
|
58
|
+
end
|
|
59
|
+
der = der[type.to_der.size..-1]
|
|
60
|
+
end
|
|
61
|
+
root
|
|
62
|
+
end
|
|
32
63
|
end
|
data/lib/rasn1/model.rb
CHANGED
|
@@ -95,15 +95,22 @@ module RASN1
|
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
# @method sequence(name, options)
|
|
98
|
+
# @param [Symbol,String] name name of object in model
|
|
99
|
+
# @param [Hash] options
|
|
98
100
|
# @see Types::Sequence#initialize
|
|
99
101
|
# @method set(name, options)
|
|
102
|
+
# @param [Symbol,String] name name of object in model
|
|
103
|
+
# @param [Hash] options
|
|
100
104
|
# @see Types::Set#initialize
|
|
101
105
|
# @method choice(name, options)
|
|
106
|
+
# @param [Symbol,String] name name of object in model
|
|
107
|
+
# @param [Hash] options
|
|
102
108
|
# @see Types::Choice#initialize
|
|
103
109
|
%w(sequence set choice).each do |type|
|
|
104
110
|
class_eval "def #{type}(name, options={})\n" \
|
|
111
|
+
" options.merge!(name: name)\n" \
|
|
105
112
|
" proc = Proc.new do |opts|\n" \
|
|
106
|
-
" Types::#{type.capitalize}.new(
|
|
113
|
+
" Types::#{type.capitalize}.new(options.merge(opts))\n" \
|
|
107
114
|
" end\n" \
|
|
108
115
|
" @root = [name, proc]\n" \
|
|
109
116
|
" @root << options[:content] unless options[:content].nil?\n" \
|
|
@@ -112,54 +119,82 @@ module RASN1
|
|
|
112
119
|
end
|
|
113
120
|
|
|
114
121
|
# @method sequence_of(name, type, options)
|
|
122
|
+
# @param [Symbol,String] name name of object in model
|
|
123
|
+
# @param [Model, Types::Base] type type for SEQUENCE OF
|
|
124
|
+
# @param [Hash] options
|
|
115
125
|
# @see Types::SequenceOf#initialize
|
|
116
126
|
# @method set_of(name, type, options)
|
|
127
|
+
# @param [Symbol,String] name name of object in model
|
|
128
|
+
# @param [Model, Types::Base] type type for SET OF
|
|
129
|
+
# @param [Hash] options
|
|
117
130
|
# @see Types::SetOf#initialize
|
|
118
131
|
%w(sequence set).each do |type|
|
|
119
132
|
klass_name = "Types::#{type.capitalize}Of"
|
|
120
133
|
class_eval "def #{type}_of(name, type, options={})\n" \
|
|
134
|
+
" options.merge!(name: name)\n" \
|
|
121
135
|
" proc = Proc.new do |opts|\n" \
|
|
122
|
-
" #{klass_name}.new(
|
|
136
|
+
" #{klass_name}.new(type, options.merge(opts))\n" \
|
|
123
137
|
" end\n" \
|
|
124
138
|
" @root = [name, proc]\n" \
|
|
125
139
|
"end"
|
|
126
140
|
end
|
|
127
141
|
|
|
128
142
|
# @method boolean(name, options)
|
|
143
|
+
# @param [Symbol,String] name name of object in model
|
|
144
|
+
# @param [Hash] options
|
|
129
145
|
# @see Types::Boolean#initialize
|
|
130
146
|
# @method integer(name, options)
|
|
147
|
+
# @param [Symbol,String] name name of object in model
|
|
148
|
+
# @param [Hash] options
|
|
131
149
|
# @see Types::Integer#initialize
|
|
132
150
|
# @method bit_string(name, options)
|
|
151
|
+
# @param [Symbol,String] name name of object in model
|
|
152
|
+
# @param [Hash] options
|
|
133
153
|
# @see Types::BitString#initialize
|
|
134
154
|
# @method octet_string(name, options)
|
|
155
|
+
# @param [Symbol,String] name name of object in model
|
|
156
|
+
# @param [Hash] options
|
|
135
157
|
# @see Types::OctetString#initialize
|
|
136
158
|
# @method null(name, options)
|
|
159
|
+
# @param [Symbol,String] name name of object in model
|
|
160
|
+
# @param [Hash] options
|
|
137
161
|
# @see Types::Null#initialize
|
|
138
162
|
# @method enumerated(name, options)
|
|
163
|
+
# @param [Symbol,String] name name of object in model
|
|
164
|
+
# @param [Hash] options
|
|
139
165
|
# @see Types::Enumerated#initialize
|
|
140
166
|
# @method utf8_string(name, options)
|
|
167
|
+
# @param [Symbol,String] name name of object in model
|
|
168
|
+
# @param [Hash] options
|
|
141
169
|
# @see Types::Utf8String#initialize
|
|
142
170
|
Types.primitives.each do |prim|
|
|
143
171
|
next if prim == Types::ObjectId
|
|
144
172
|
class_eval "def #{prim.type.downcase.gsub(/\s+/, '_')}(name, options={})\n" \
|
|
173
|
+
" options.merge!(name: name)\n" \
|
|
145
174
|
" proc = Proc.new do |opts|\n" \
|
|
146
|
-
" #{prim.to_s}.new(
|
|
175
|
+
" #{prim.to_s}.new(options.merge(opts))\n" \
|
|
147
176
|
" end\n" \
|
|
148
177
|
" @root = [name, proc]\n" \
|
|
149
178
|
"end"
|
|
150
179
|
end
|
|
151
180
|
|
|
181
|
+
# @param [Symbol,String] name name of object in model
|
|
182
|
+
# @param [Hash] options
|
|
152
183
|
# @note This method is named +objectid+ and not +object_id+ to not override
|
|
153
184
|
# +Object#object_id+.
|
|
154
185
|
# @see Types::ObjectId#initialize
|
|
155
186
|
def objectid(name, options={})
|
|
156
|
-
|
|
187
|
+
options.merge!(name: name)
|
|
188
|
+
proc = Proc.new { |opts| Types::ObjectId.new(options.merge(opts)) }
|
|
157
189
|
@root = [name, proc]
|
|
158
190
|
end
|
|
159
191
|
|
|
192
|
+
# @param [Symbol,String] name name of object in model
|
|
193
|
+
# @param [Hash] options
|
|
160
194
|
# @see Types::Any#initialize
|
|
161
195
|
def any(name, options={})
|
|
162
|
-
|
|
196
|
+
options.merge!(name: name)
|
|
197
|
+
proc = Proc.new { |opts| Types::Any.new(options.merge(opts)) }
|
|
163
198
|
@root = [name, proc]
|
|
164
199
|
end
|
|
165
200
|
|
|
@@ -186,7 +221,7 @@ module RASN1
|
|
|
186
221
|
# @param [Hash] args
|
|
187
222
|
def initialize(args={})
|
|
188
223
|
root = generate_root
|
|
189
|
-
set_elements
|
|
224
|
+
set_elements(*root)
|
|
190
225
|
initialize_elements self, args
|
|
191
226
|
end
|
|
192
227
|
|
|
@@ -209,7 +244,7 @@ module RASN1
|
|
|
209
244
|
# Get name frm root type
|
|
210
245
|
# @return [String,Symbol]
|
|
211
246
|
def name
|
|
212
|
-
@
|
|
247
|
+
@root
|
|
213
248
|
end
|
|
214
249
|
|
|
215
250
|
# Get elements names
|
|
@@ -221,7 +256,7 @@ module RASN1
|
|
|
221
256
|
# Return a hash image of model
|
|
222
257
|
# @return [Hash]
|
|
223
258
|
def to_h
|
|
224
|
-
|
|
259
|
+
private_to_h
|
|
225
260
|
end
|
|
226
261
|
|
|
227
262
|
# @return [String]
|
|
@@ -328,27 +363,32 @@ module RASN1
|
|
|
328
363
|
end
|
|
329
364
|
end
|
|
330
365
|
|
|
331
|
-
def private_to_h(element)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
366
|
+
def private_to_h(element=nil)
|
|
367
|
+
my_element = element
|
|
368
|
+
my_element = root if my_element.nil?
|
|
369
|
+
my_element = my_element.root if my_element.is_a?(Model)
|
|
370
|
+
value = case my_element
|
|
371
|
+
when Types::SequenceOf
|
|
372
|
+
if my_element.of_type < Model
|
|
373
|
+
my_element.value.map { |el| el.to_h.values.first }
|
|
374
|
+
else
|
|
375
|
+
my_element.value.map { |el| private_to_h(el) }
|
|
376
|
+
end
|
|
377
|
+
when Types::Sequence
|
|
378
|
+
seq = my_element.value.map do |el|
|
|
379
|
+
next if el.optional? and el.value.nil?
|
|
380
|
+
name = el.is_a?(Model) ? @elements.key(el) : el.name
|
|
381
|
+
[name, private_to_h(el)]
|
|
382
|
+
end
|
|
383
|
+
seq.compact!
|
|
384
|
+
Hash[seq]
|
|
385
|
+
else
|
|
386
|
+
my_element.value
|
|
387
|
+
end
|
|
388
|
+
if element.nil?
|
|
389
|
+
{ @root => value }
|
|
350
390
|
else
|
|
351
|
-
|
|
391
|
+
value
|
|
352
392
|
end
|
|
353
393
|
end
|
|
354
394
|
end
|
data/lib/rasn1/types.rb
CHANGED
|
@@ -6,15 +6,42 @@ module RASN1
|
|
|
6
6
|
# Give all primitive types
|
|
7
7
|
# @return [Array<Types::Primitive>]
|
|
8
8
|
def self.primitives
|
|
9
|
-
self.constants.map { |c| Types.const_get(c) }.
|
|
10
|
-
|
|
9
|
+
@primitives ||= self.constants.map { |c| Types.const_get(c) }.
|
|
10
|
+
select { |klass| klass < Primitive }
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
# Give all constructed types
|
|
14
14
|
# @return [Array<Types::Constructed>]
|
|
15
15
|
def self.constructed
|
|
16
|
-
self.constants.map { |c| Types.const_get(c) }.
|
|
17
|
-
|
|
16
|
+
@constructed ||= self.constants.map { |c| Types.const_get(c) }.
|
|
17
|
+
select { |klass| klass < Constructed }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Give ASN.1 type from an integer. If +tag+ is unknown, return a {Types::Base}
|
|
21
|
+
# object.
|
|
22
|
+
# @param [Integer] tag
|
|
23
|
+
# @return [Types::Base]
|
|
24
|
+
# @raise [ASN1Error] +tag+ is out of range
|
|
25
|
+
def self.tag2type(tag)
|
|
26
|
+
raise ASN1Error, "tag is out of range" if tag > 0xff
|
|
27
|
+
|
|
28
|
+
if !defined? @tag2types
|
|
29
|
+
constructed = self.constructed - [Types::SequenceOf, Types::SetOf]
|
|
30
|
+
primitives = self.primitives - [Types::Enumerated]
|
|
31
|
+
ary = [primitives, constructed].flatten.map do |type|
|
|
32
|
+
next unless type.const_defined? :TAG
|
|
33
|
+
[type::TAG, type]
|
|
34
|
+
end
|
|
35
|
+
@tag2types = Hash[ary]
|
|
36
|
+
@tag2types.default = Types::Base
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
klass = @tag2types[tag & 0xdf] # Remove CONSTRUCTED bit
|
|
40
|
+
is_constructed = (tag & 0x20) == 0x20
|
|
41
|
+
asn1class = Types::Base::CLASSES.key(tag & 0xc0)
|
|
42
|
+
options = { class: asn1class, constructed: is_constructed }
|
|
43
|
+
options[:tag_value] = (tag & 0x1f) if klass == Types::Base
|
|
44
|
+
klass.new(options)
|
|
18
45
|
end
|
|
19
46
|
end
|
|
20
47
|
end
|
data/lib/rasn1/types/any.rb
CHANGED
|
@@ -13,7 +13,7 @@ module RASN1
|
|
|
13
13
|
when Base, Model
|
|
14
14
|
@value.to_der
|
|
15
15
|
when nil
|
|
16
|
-
Null.new
|
|
16
|
+
Null.new.to_der
|
|
17
17
|
else
|
|
18
18
|
@value.to_s
|
|
19
19
|
end
|
|
@@ -33,14 +33,15 @@ module RASN1
|
|
|
33
33
|
def inspect(level=0)
|
|
34
34
|
str = ''
|
|
35
35
|
str << ' ' * level if level > 0
|
|
36
|
+
str << "#{@name} " unless @name.nil?
|
|
36
37
|
if @value.nil?
|
|
37
|
-
str << "
|
|
38
|
+
str << "(ANY) NULL"
|
|
38
39
|
elsif @value.is_a?(OctetString)
|
|
39
|
-
str << "
|
|
40
|
+
str << "(ANY) #{@value.type}: #{value.value.inspect}"
|
|
40
41
|
elsif @value.class < Base
|
|
41
|
-
str << "
|
|
42
|
+
str << "(ANY) #{@value.type}: #{value.value}"
|
|
42
43
|
else
|
|
43
|
-
str << "
|
|
44
|
+
str << "(ANY) #{value.to_s.inspect}"
|
|
44
45
|
end
|
|
45
46
|
end
|
|
46
47
|
end
|
data/lib/rasn1/types/base.rb
CHANGED
|
@@ -33,15 +33,15 @@ module RASN1
|
|
|
33
33
|
# -- private tag
|
|
34
34
|
# PType ::= [PRIVATE 2] EXPLICIT INTEGER
|
|
35
35
|
# These types may be defined as:
|
|
36
|
-
# ctype = RASN1::Types::Integer.new(
|
|
37
|
-
# atype = RASN1::Types::Integer.new(
|
|
38
|
-
# ptype = RASN1::Types::Integer.new(
|
|
36
|
+
# ctype = RASN1::Types::Integer.new(explicit: 0) # with explicit, default #asn1_class is :context
|
|
37
|
+
# atype = RASN1::Types::Integer.new(explicit: 1, class: :application)
|
|
38
|
+
# ptype = RASN1::Types::Integer.new(explicit: 2, class: :private)
|
|
39
39
|
# Sometimes, an EXPLICIT type should be CONSTRUCTED. To do that, use +:constructed+
|
|
40
40
|
# option:
|
|
41
|
-
# ptype = RASN1::Types::Integer.new(
|
|
41
|
+
# ptype = RASN1::Types::Integer.new(explicit: 2, class: :private, constructed: true)
|
|
42
42
|
#
|
|
43
43
|
# Implicit tagged values may also be defined:
|
|
44
|
-
# ctype_implicit = RASN1::Types::Integer.new(
|
|
44
|
+
# ctype_implicit = RASN1::Types::Integer.new(implicit: 0)
|
|
45
45
|
# @author Sylvain Daubert
|
|
46
46
|
class Base
|
|
47
47
|
# Allowed ASN.1 tag classes
|
|
@@ -58,8 +58,8 @@ module RASN1
|
|
|
58
58
|
# Length value for indefinite length
|
|
59
59
|
INDEFINITE_LENGTH = 0x80
|
|
60
60
|
|
|
61
|
-
# @return [
|
|
62
|
-
|
|
61
|
+
# @return [String,nil]
|
|
62
|
+
attr_reader :name
|
|
63
63
|
# @return [Symbol]
|
|
64
64
|
attr_reader :asn1_class
|
|
65
65
|
# @return [Object,nil] default value, if defined
|
|
@@ -75,23 +75,40 @@ module RASN1
|
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
|
|
78
|
-
# @
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
|
|
91
|
-
|
|
78
|
+
# @overload initialize(options={})
|
|
79
|
+
# @param [Hash] options
|
|
80
|
+
# @option options [Symbol] :class ASN.1 tag class. Default value is +:universal+.
|
|
81
|
+
# If +:explicit+ or +:implicit:+ is defined, default value is +:context+.
|
|
82
|
+
# @option options [::Boolean] :optional define this tag as optional. Default
|
|
83
|
+
# is +false+
|
|
84
|
+
# @option options [Object] :default default value for DEFAULT tag
|
|
85
|
+
# @option options [Object] :value value to set
|
|
86
|
+
# @option options [::Integer] :implicit define an IMPLICIT tagged type
|
|
87
|
+
# @option options [::Integer] :explicit define an EXPLICIT tagged type
|
|
88
|
+
# @option options [::Boolean] :constructed if +true+, set type as constructed.
|
|
89
|
+
# May only be used when +:explicit+ is defined, else it is discarded.
|
|
90
|
+
# @option options [::String] :name name for this node
|
|
91
|
+
# @overload initialize(value, options={})
|
|
92
|
+
# @param [Object] value value to set for this ASN.1 object
|
|
93
|
+
# @param [Hash] options
|
|
94
|
+
# @option options [Symbol] :class ASN.1 tag class. Default value is +:universal+.
|
|
95
|
+
# If +:explicit+ or +:implicit:+ is defined, default value is +:context+.
|
|
96
|
+
# @option options [::Boolean] :optional define this tag as optional. Default
|
|
97
|
+
# is +false+
|
|
98
|
+
# @option options [Object] :default default value for DEFAULT tag
|
|
99
|
+
# @option options [::Integer] :implicit define an IMPLICIT tagged type
|
|
100
|
+
# @option options [::Integer] :explicit define an EXPLICIT tagged type
|
|
101
|
+
# @option options [::Boolean] :constructed if +true+, set type as constructed.
|
|
102
|
+
# May only be used when +:explicit+ is defined, else it is discarded.
|
|
103
|
+
# @option options [::String] :name name for this node
|
|
104
|
+
def initialize(value_or_options={}, options={})
|
|
92
105
|
@constructed = nil
|
|
93
|
-
|
|
94
|
-
|
|
106
|
+
if value_or_options.is_a? Hash
|
|
107
|
+
set_options value_or_options
|
|
108
|
+
else
|
|
109
|
+
set_options options
|
|
110
|
+
@value = value_or_options
|
|
111
|
+
end
|
|
95
112
|
end
|
|
96
113
|
|
|
97
114
|
# Used by +#dup+ and +#clone+. Deep copy @value.
|
|
@@ -142,11 +159,7 @@ module RASN1
|
|
|
142
159
|
# SHOULD respond to +#value_to_der+.
|
|
143
160
|
# @return [String] DER-formated string
|
|
144
161
|
def to_der
|
|
145
|
-
|
|
146
|
-
build_tag
|
|
147
|
-
else
|
|
148
|
-
raise NotImplementedError, 'should be implemented by subclasses'
|
|
149
|
-
end
|
|
162
|
+
build_tag
|
|
150
163
|
end
|
|
151
164
|
|
|
152
165
|
# @return [::Boolean] +true+ if this is a primitive type
|
|
@@ -168,10 +181,12 @@ module RASN1
|
|
|
168
181
|
# Get tag value
|
|
169
182
|
# @return [Integer]
|
|
170
183
|
def tag
|
|
171
|
-
pc = if
|
|
184
|
+
pc = if @constructed.nil?
|
|
172
185
|
self.class::ASN1_PC
|
|
173
|
-
|
|
186
|
+
elsif @constructed # true
|
|
174
187
|
Constructed::ASN1_PC
|
|
188
|
+
else # false
|
|
189
|
+
0
|
|
175
190
|
end
|
|
176
191
|
(@tag_value || self.class::TAG) | CLASSES[@asn1_class] | pc
|
|
177
192
|
end
|
|
@@ -208,7 +223,17 @@ module RASN1
|
|
|
208
223
|
def inspect(level=0)
|
|
209
224
|
str = ''
|
|
210
225
|
str << ' ' * level if level > 0
|
|
211
|
-
str << "#{name}
|
|
226
|
+
str << "#{@name} " unless @name.nil?
|
|
227
|
+
if self.class == Base
|
|
228
|
+
str << "#{type} (0x#{'%02x' % tag}): "
|
|
229
|
+
if @value.is_a?(Base)
|
|
230
|
+
str << value.inspect(level+1)
|
|
231
|
+
else
|
|
232
|
+
str << value.inspect
|
|
233
|
+
end
|
|
234
|
+
else
|
|
235
|
+
str << "#{type}: #{value.inspect}"
|
|
236
|
+
end
|
|
212
237
|
end
|
|
213
238
|
|
|
214
239
|
# Objects are equal if they have same class AND same DER
|
|
@@ -220,12 +245,26 @@ module RASN1
|
|
|
220
245
|
|
|
221
246
|
private
|
|
222
247
|
|
|
248
|
+
def value_to_der
|
|
249
|
+
case @value
|
|
250
|
+
when Base
|
|
251
|
+
@value.to_der
|
|
252
|
+
else
|
|
253
|
+
@value.to_s
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def der_to_value(der, ber:false)
|
|
258
|
+
@value = der
|
|
259
|
+
end
|
|
260
|
+
|
|
223
261
|
def set_options(options)
|
|
224
262
|
set_class options[:class]
|
|
225
263
|
set_optional options[:optional]
|
|
226
264
|
set_default options[:default]
|
|
227
265
|
set_tag options
|
|
228
266
|
@value = options[:value]
|
|
267
|
+
@name = options[:name]
|
|
229
268
|
end
|
|
230
269
|
|
|
231
270
|
def set_class(asn1_class)
|
|
@@ -251,6 +290,8 @@ module RASN1
|
|
|
251
290
|
@default = default
|
|
252
291
|
end
|
|
253
292
|
|
|
293
|
+
# handle undocumented option +:tag_value+, used internally by
|
|
294
|
+
# {RASN1.parse} to parse non-universal class tags.
|
|
254
295
|
def set_tag(options)
|
|
255
296
|
if options[:explicit]
|
|
256
297
|
@tag = :explicit
|
|
@@ -259,6 +300,10 @@ module RASN1
|
|
|
259
300
|
elsif options[:implicit]
|
|
260
301
|
@tag = :implicit
|
|
261
302
|
@tag_value = options[:implicit]
|
|
303
|
+
@constructed = options[:constructed]
|
|
304
|
+
elsif options[:tag_value]
|
|
305
|
+
@tag_value = options[:tag_value]
|
|
306
|
+
@constructed = options[:constructed]
|
|
262
307
|
end
|
|
263
308
|
|
|
264
309
|
@asn1_class = :context if @tag and @asn1_class == :universal
|
|
@@ -330,14 +375,14 @@ module RASN1
|
|
|
330
375
|
|
|
331
376
|
if length == INDEFINITE_LENGTH
|
|
332
377
|
if primitive?
|
|
333
|
-
raise ASN1Error, "malformed #{type} TAG
|
|
378
|
+
raise ASN1Error, "malformed #{type} TAG: indefinite length " \
|
|
334
379
|
"forbidden for primitive types"
|
|
335
380
|
else
|
|
336
381
|
if ber
|
|
337
|
-
raise NotImplementedError, "TAG
|
|
382
|
+
raise NotImplementedError, "TAG: indefinite length not " \
|
|
338
383
|
"supported yet"
|
|
339
384
|
else
|
|
340
|
-
raise ASN1Error, "TAG
|
|
385
|
+
raise ASN1Error, "TAG: indefinite length forbidden in DER " \
|
|
341
386
|
"encoding"
|
|
342
387
|
end
|
|
343
388
|
end
|
|
@@ -357,12 +402,11 @@ module RASN1
|
|
|
357
402
|
end
|
|
358
403
|
|
|
359
404
|
def explicit_type
|
|
360
|
-
self.class.new
|
|
405
|
+
self.class.new
|
|
361
406
|
end
|
|
362
407
|
|
|
363
408
|
def raise_tag_error(expected_tag, tag)
|
|
364
409
|
msg = "Expected #{tag2name(expected_tag)} but get #{tag2name(tag)}"
|
|
365
|
-
msg << " for #@name"
|
|
366
410
|
raise ASN1Error, msg
|
|
367
411
|
end
|
|
368
412
|
|
|
@@ -9,28 +9,32 @@ module RASN1
|
|
|
9
9
|
# @return [Integer] bit length of bit string
|
|
10
10
|
attr_accessor :bit_length
|
|
11
11
|
|
|
12
|
-
# @
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
|
|
12
|
+
# @overload initialize(options={})
|
|
13
|
+
# @param [Hash] options
|
|
14
|
+
# @option options [Object] :bit_length default bit_length value. Should be
|
|
15
|
+
# present if +:default+ is set
|
|
16
|
+
# @overload initialize(value, options={})
|
|
17
|
+
# @param [Object] value value to set for this ASN.1 object
|
|
18
|
+
# @param [Hash] options
|
|
19
|
+
# @option options [Object] :bit_length default bit_length value. Should be
|
|
20
|
+
# present if +:default+ is set
|
|
21
|
+
# @see Base#initialize common options to all ASN.1 types
|
|
22
|
+
def initialize(value_or_options={}, options={})
|
|
21
23
|
super
|
|
24
|
+
opts = value_or_options.is_a?(Hash) ? value_or_options : options
|
|
22
25
|
if @default
|
|
23
|
-
if
|
|
26
|
+
if opts[:bit_length].nil?
|
|
24
27
|
raise ASN1Error, "TAG #@name: default bit length is not defined"
|
|
25
28
|
end
|
|
26
|
-
@default_bit_length =
|
|
29
|
+
@default_bit_length = opts[:bit_length]
|
|
27
30
|
end
|
|
28
31
|
end
|
|
29
32
|
|
|
30
33
|
def inspect(level=0)
|
|
31
34
|
str = ''
|
|
32
35
|
str << ' ' * level if level > 0
|
|
33
|
-
str << "#{name}
|
|
36
|
+
str << "#{name} " unless @name.nil?
|
|
37
|
+
str << "#{type}: #{value.inspect} (bit length: #{bit_length})"
|
|
34
38
|
end
|
|
35
39
|
|
|
36
40
|
private
|
|
@@ -14,6 +14,7 @@ module RASN1
|
|
|
14
14
|
when Array
|
|
15
15
|
str = ''
|
|
16
16
|
str << ' ' * level if level > 0
|
|
17
|
+
str << "#{@name} " unless @name.nil?
|
|
17
18
|
level = level.abs
|
|
18
19
|
str << "#{type}:\n"
|
|
19
20
|
level += 1
|
|
@@ -21,7 +22,9 @@ module RASN1
|
|
|
21
22
|
case item
|
|
22
23
|
when Base, Model
|
|
23
24
|
next if item.optional? and item.value.nil?
|
|
24
|
-
str << ' ' * level
|
|
25
|
+
str << ' ' * level
|
|
26
|
+
str << "#{item.name} " unless item.name.nil?
|
|
27
|
+
str << "#{item.inspect(level)}\n"
|
|
25
28
|
else
|
|
26
29
|
str << item.inspect
|
|
27
30
|
end
|
|
@@ -21,20 +21,24 @@ module RASN1
|
|
|
21
21
|
# @return [Hash]
|
|
22
22
|
attr_reader :enum
|
|
23
23
|
|
|
24
|
-
# @
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# is
|
|
29
|
-
# @
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
|
|
24
|
+
# @overload initialize(options={})
|
|
25
|
+
# @option options [Hash] :enum enumeration hash. Keys are names, and values
|
|
26
|
+
# are integers. This key is mandatory.
|
|
27
|
+
# @raise [EnumeratedError] +:enum+ key is not present
|
|
28
|
+
# @raise [EnumeratedError] +:default+ value is unknown
|
|
29
|
+
# @overload initialize(value, options={})
|
|
30
|
+
# @param [Object] value value to set for this ASN.1 object
|
|
31
|
+
# @option options [Hash] :enum enumeration hash. Keys are names, and values
|
|
32
|
+
# are integers. This key is mandatory.
|
|
33
|
+
# @raise [EnumeratedError] +:enum+ key is not present
|
|
34
|
+
# @raise [EnumeratedError] +:default+ value is unknown
|
|
35
|
+
# @see Base#initialize common options to all ASN.1 types
|
|
36
|
+
def initialize(value_or_options={}, options={})
|
|
35
37
|
super
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
opts = value_or_options.is_a?(Hash) ? value_or_options : options
|
|
39
|
+
|
|
40
|
+
raise EnumeratedError, 'no enumeration given' unless opts.has_key? :enum
|
|
41
|
+
@enum = opts[:enum]
|
|
38
42
|
|
|
39
43
|
case @default
|
|
40
44
|
when String,Symbol
|
|
@@ -16,22 +16,8 @@ module RASN1
|
|
|
16
16
|
def inspect(level=0)
|
|
17
17
|
str = ''
|
|
18
18
|
str << ' ' * level if level > 0
|
|
19
|
-
str << "#{name}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
private
|
|
23
|
-
|
|
24
|
-
def value_to_der
|
|
25
|
-
case @value
|
|
26
|
-
when Base
|
|
27
|
-
@value.to_der
|
|
28
|
-
else
|
|
29
|
-
@value.to_s
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def der_to_value(der, ber:false)
|
|
34
|
-
@value = der
|
|
19
|
+
str << "#{@name} " unless @name.nil?
|
|
20
|
+
str << "#{type}: #{value.inspect}"
|
|
35
21
|
end
|
|
36
22
|
end
|
|
37
23
|
end
|
data/lib/rasn1/types/sequence.rb
CHANGED
|
@@ -14,9 +14,9 @@ module RASN1
|
|
|
14
14
|
# do:
|
|
15
15
|
# seq = RASN1::Types::Sequence.new(:record)
|
|
16
16
|
# seq.value = [
|
|
17
|
-
# RASN1::Types::Integer(:id),
|
|
18
|
-
# RASN1::Types::Integer(:
|
|
19
|
-
# RASN1::Types::Integer(:
|
|
17
|
+
# RASN1::Types::Integer.new(:id),
|
|
18
|
+
# RASN1::Types::Integer.new(:room, explicit: 0, optional: true),
|
|
19
|
+
# RASN1::Types::Integer.new(:house, implicit: 1, default: 0)
|
|
20
20
|
# ]
|
|
21
21
|
#
|
|
22
22
|
# A sequence may also be used without value to not parse sequence content:
|
|
@@ -27,20 +27,10 @@ module RASN1
|
|
|
27
27
|
class Sequence < Constructed
|
|
28
28
|
TAG = 0x10
|
|
29
29
|
|
|
30
|
-
# @
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
# @option options [::Boolean] :optional define this tag as optional. Default
|
|
35
|
-
# is +false+
|
|
36
|
-
# @option options [Object] :default default value for DEFAULT tag
|
|
37
|
-
# @option options [Object] :value value to set (default is +[]+)
|
|
38
|
-
# @option options [::Integer] :implicit define an IMPLICIT tagged type
|
|
39
|
-
# @option options [::Integer] :explicit define an EXPLICIT tagged type
|
|
40
|
-
# @option options [::Boolean] :constructed if +true+, set type as constructed.
|
|
41
|
-
# May only be used when +:explicit+ is defined, else it is discarded.
|
|
42
|
-
def initialize(name, options={})
|
|
43
|
-
super(name, { value: [] }.merge(options))
|
|
30
|
+
# @see Base#initialize
|
|
31
|
+
def initialize(value_or_options={}, options={})
|
|
32
|
+
super
|
|
33
|
+
@value ||= []
|
|
44
34
|
end
|
|
45
35
|
|
|
46
36
|
def initialize_copy(other)
|
|
@@ -53,8 +53,8 @@ module RASN1
|
|
|
53
53
|
# @param [Symbol, String] name name for this tag in grammar
|
|
54
54
|
# @param [Class, Base] of_type base type for sequence of
|
|
55
55
|
# @see Base#initialize
|
|
56
|
-
def initialize(
|
|
57
|
-
super(
|
|
56
|
+
def initialize(of_type, options={})
|
|
57
|
+
super(options)
|
|
58
58
|
@of_type = of_type
|
|
59
59
|
@value = []
|
|
60
60
|
end
|
|
@@ -70,10 +70,10 @@ module RASN1
|
|
|
70
70
|
def <<(obj)
|
|
71
71
|
if of_type_class < Primitive
|
|
72
72
|
raise ASN1Error, 'object to add should be an Array' unless obj.is_a?(Array)
|
|
73
|
-
@value += obj.map { |item| @of_type.new(
|
|
73
|
+
@value += obj.map { |item| @of_type.new(item) }
|
|
74
74
|
elsif composed_of_type?
|
|
75
75
|
raise ASN1Error, 'object to add should be an Array' unless obj.is_a?(Array)
|
|
76
|
-
new_value = of_type_class.new
|
|
76
|
+
new_value = of_type_class.new
|
|
77
77
|
@of_type.value.each_with_index do |type, i|
|
|
78
78
|
type2 = type.dup
|
|
79
79
|
type2.value = obj[i]
|
|
@@ -161,7 +161,7 @@ module RASN1
|
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
def explicit_type
|
|
164
|
-
self.class.new(
|
|
164
|
+
self.class.new(self.of_type)
|
|
165
165
|
end
|
|
166
166
|
end
|
|
167
167
|
end
|
data/lib/rasn1/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rasn1
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sylvain Daubert
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-12-
|
|
11
|
+
date: 2017-12-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: yard
|