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