rasn1 0.16.2 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +25 -10
- data/lib/rasn1/errors.rb +2 -2
- data/lib/rasn1/model/accel.rb +229 -0
- data/lib/rasn1/model.rb +125 -211
- data/lib/rasn1/tracer.rb +34 -14
- data/lib/rasn1/types/any.rb +24 -3
- data/lib/rasn1/types/base.rb +132 -36
- data/lib/rasn1/types/bit_string.rb +18 -5
- data/lib/rasn1/types/boolean.rb +14 -3
- data/lib/rasn1/types/choice.rb +39 -23
- data/lib/rasn1/types/constrained.rb +4 -3
- data/lib/rasn1/types/constructed.rb +4 -2
- data/lib/rasn1/types/enumerated.rb +9 -8
- data/lib/rasn1/types/generalized_time.rb +32 -13
- data/lib/rasn1/types/integer.rb +67 -11
- data/lib/rasn1/types/null.rb +7 -3
- data/lib/rasn1/types/numeric_string.rb +14 -2
- data/lib/rasn1/types/object_id.rb +15 -4
- data/lib/rasn1/types/octet_string.rb +3 -3
- data/lib/rasn1/types/primitive.rb +4 -0
- data/lib/rasn1/types/printable_string.rb +9 -2
- data/lib/rasn1/types/sequence.rb +7 -3
- data/lib/rasn1/types/sequence_of.rb +28 -8
- data/lib/rasn1/types/set_of.rb +1 -1
- data/lib/rasn1/types/utc_time.rb +7 -2
- data/lib/rasn1/types.rb +5 -5
- data/lib/rasn1/version.rb +1 -1
- data/lib/rasn1/wrapper.rb +38 -7
- data/lib/rasn1.rb +8 -7
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 67e24db40c3ec0a8e7d7ad23211549c1aadda9511ea73f632034a4cdefa97ae0
|
|
4
|
+
data.tar.gz: d8847b0b52cce0014f02772077da519df146c14a1f65ffebc72cc206e888b0cd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 12da7b29112a40073dd64e3eb949412cd941932d63fb87e2cf36cf020c1df784cdd85e6e2cd04113f8bf74e7b16c630fad2346b885933874f86dcd329f42511b
|
|
7
|
+
data.tar.gz: a5294cfc1a3ebc0430c1be31558ed1e33ac97e5d87ad8ff3c14d6c8633b251d53b33e7818762f46bb6272c4f71da439a42aa86f79413c3af405b5b3d076777a3
|
data/README.md
CHANGED
|
@@ -52,7 +52,9 @@ ComplexRecord ::= SEQUENCE {
|
|
|
52
52
|
}
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
### Create
|
|
55
|
+
### Create an ASN.1 model
|
|
56
|
+
|
|
57
|
+
A model is created this way:
|
|
56
58
|
|
|
57
59
|
```ruby
|
|
58
60
|
class Record < RASN1::Model
|
|
@@ -63,14 +65,31 @@ class Record < RASN1::Model
|
|
|
63
65
|
end
|
|
64
66
|
```
|
|
65
67
|
|
|
68
|
+
or, this ways in a more rubyish style:
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
# This Record class is defined as a sequence conaining:
|
|
72
|
+
# * an ID (integer)
|
|
73
|
+
# * a room number (integer, with explicit tag, optional)
|
|
74
|
+
# * a house if (integer, with explicit tag and a default value)
|
|
75
|
+
class Record < RASN1::Model
|
|
76
|
+
sequence :record do
|
|
77
|
+
integer(:id)
|
|
78
|
+
integer(:room, implicit: 0, optional: true)
|
|
79
|
+
integer(:house, implicit: 1, default: 0)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
```
|
|
83
|
+
|
|
66
84
|
More comple classes may be designed by nesting simple classes. For example:
|
|
67
85
|
|
|
68
86
|
```ruby
|
|
69
87
|
class ComplexRecord < RASN1::Model
|
|
70
|
-
sequence :cplx_record
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
88
|
+
sequence :cplx_record do
|
|
89
|
+
boolean(:bool)
|
|
90
|
+
octet_string(:data, explicit: 0)
|
|
91
|
+
model(:a_record, Record) # Use another model in model
|
|
92
|
+
end
|
|
74
93
|
end
|
|
75
94
|
```
|
|
76
95
|
|
|
@@ -115,10 +134,6 @@ record.set id: 124, house: 155
|
|
|
115
134
|
record.to_der # => String
|
|
116
135
|
```
|
|
117
136
|
|
|
118
|
-
### More information
|
|
119
|
-
|
|
120
|
-
see <https://github.com/sdaubert/rasn1/wiki>
|
|
121
|
-
|
|
122
137
|
## Contributing
|
|
123
138
|
|
|
124
|
-
Bug reports and pull requests are welcome on GitHub at <https://
|
|
139
|
+
Bug reports and pull requests are welcome on GitHub at <https://codeberg.org/lemontree55/rasn1>.
|
data/lib/rasn1/errors.rb
CHANGED
|
@@ -26,7 +26,7 @@ module RASN1
|
|
|
26
26
|
|
|
27
27
|
# CHOICE error: {Types::Choice#chosen} not set
|
|
28
28
|
class ChoiceError < RASN1::Error
|
|
29
|
-
# @param [Types::Base]
|
|
29
|
+
# @param object [Types::Base]
|
|
30
30
|
def initialize(object)
|
|
31
31
|
@object = object
|
|
32
32
|
super()
|
|
@@ -42,7 +42,7 @@ module RASN1
|
|
|
42
42
|
# @version 0.11.0
|
|
43
43
|
# @author Sylvain Daubert
|
|
44
44
|
class ConstraintError < Error
|
|
45
|
-
# @param [Types::Base]
|
|
45
|
+
# @param object [Types::Base]
|
|
46
46
|
def initialize(object)
|
|
47
47
|
@object = object
|
|
48
48
|
super()
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This file is part of RASN1
|
|
4
|
+
# See https://codeberg.org/lemontree55/rasn1 for more informations
|
|
5
|
+
# Copyright (C) 2016-2024 Sylvain Daubert <sylvain.daubert@laposte.net>
|
|
6
|
+
# Copyright (C) 2024 LemonTree55 <lenontree@proton.me>
|
|
7
|
+
# This program is published under MIT license.
|
|
8
|
+
|
|
9
|
+
module RASN1
|
|
10
|
+
class Model
|
|
11
|
+
# Define helper methods to define models
|
|
12
|
+
# @author Sylvain Daubert
|
|
13
|
+
module Accel
|
|
14
|
+
# @return [Hash]
|
|
15
|
+
attr_reader :options
|
|
16
|
+
|
|
17
|
+
# On inheritance, create +@elements+ class variable
|
|
18
|
+
# @param klass [Class]
|
|
19
|
+
# @return [void]
|
|
20
|
+
def inherited(klass)
|
|
21
|
+
super
|
|
22
|
+
current_elements = @elements
|
|
23
|
+
klass.class_eval { @elements = current_elements.dup }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @since 0.17.0
|
|
27
|
+
def elements
|
|
28
|
+
return @elements unless @elements.nil?
|
|
29
|
+
|
|
30
|
+
@elements = []
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Use another model in this model
|
|
34
|
+
# @param name [String,Symbol]
|
|
35
|
+
# @param model_klass [Class]
|
|
36
|
+
# @return [Elem]
|
|
37
|
+
def model(name, model_klass)
|
|
38
|
+
push_element(ModelElem.new(name, model_klass))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# @since 0.17.0
|
|
42
|
+
# @param [BaseElem, WrapElem, ModelElem] elem
|
|
43
|
+
# @return [BaseElem, WrapElem, ModelElem] elem
|
|
44
|
+
def push_element(elem)
|
|
45
|
+
elements << elem
|
|
46
|
+
elem
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @since 0.17.0
|
|
50
|
+
def root
|
|
51
|
+
elements.last
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @since 0.17.0
|
|
55
|
+
def root=(elem)
|
|
56
|
+
if elements.empty?
|
|
57
|
+
elements << elem
|
|
58
|
+
else
|
|
59
|
+
elements[-1] = elem
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @overload wrapper(element, options={})
|
|
64
|
+
# Use a {Wrapper} around a {Types::Base} or a {Model} object
|
|
65
|
+
# @param element [Types::Base,Model]
|
|
66
|
+
# @param options [Hash]
|
|
67
|
+
# @return [WrapElem]
|
|
68
|
+
# @since 0.12
|
|
69
|
+
# @overload(options={})
|
|
70
|
+
# @param options [Hash]
|
|
71
|
+
# @return [WrapElem]
|
|
72
|
+
# @yieldreturn [BaseElem, ModelElem] element to wrapp
|
|
73
|
+
# @since 0.17.0
|
|
74
|
+
def wrapper(element_or_options={}, options={}, &)
|
|
75
|
+
case element_or_options
|
|
76
|
+
when Hash
|
|
77
|
+
element = generate_content(&).last
|
|
78
|
+
options = element_or_options
|
|
79
|
+
else
|
|
80
|
+
element = element_or_options
|
|
81
|
+
end
|
|
82
|
+
push_element(WrapElem.new(element, options))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Update options of root element.
|
|
86
|
+
# May be used when subclassing.
|
|
87
|
+
# class Model1 < RASN1::Model
|
|
88
|
+
# sequence :seq, implicit: 0,
|
|
89
|
+
# content: [bool(:bool), integer(:int)]
|
|
90
|
+
# end
|
|
91
|
+
#
|
|
92
|
+
# # same as Model1 but with implicit tag set to 1
|
|
93
|
+
# class Model2 < Model1
|
|
94
|
+
# root_options implicit: 1
|
|
95
|
+
# end
|
|
96
|
+
# @param options [Hash]
|
|
97
|
+
# @return [void]
|
|
98
|
+
# @since 0.12.0 may change name through +:name+
|
|
99
|
+
def root_options(options)
|
|
100
|
+
@options = options
|
|
101
|
+
return unless options.key?(:name)
|
|
102
|
+
|
|
103
|
+
self.root = root.dup
|
|
104
|
+
root.name = options[:name]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @private
|
|
108
|
+
# @param accel_name [String,Symbol]
|
|
109
|
+
# @param klass [Class]
|
|
110
|
+
# @since 0.11.0
|
|
111
|
+
# @since 0.12.0 track source location on error (adfoster-r7)
|
|
112
|
+
def define_type_accel_base(accel_name, klass)
|
|
113
|
+
singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
|
114
|
+
def #{accel_name}(name, options={}) # def sequence(name, type, options)
|
|
115
|
+
options[:name] = name
|
|
116
|
+
proc = proc do |opts|
|
|
117
|
+
#{klass}.new(options.merge(opts)) # Sequence.new(options.merge(opts))
|
|
118
|
+
end
|
|
119
|
+
push_element(BaseElem.new(name, proc, nil))
|
|
120
|
+
end
|
|
121
|
+
EVAL
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @private
|
|
125
|
+
# @param accel_name [String,Symbol]
|
|
126
|
+
# @param klass [Class]
|
|
127
|
+
# @since 0.17.0
|
|
128
|
+
def define_type_accel_container(accel_name, klass)
|
|
129
|
+
singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
|
130
|
+
def #{accel_name}(name, options={}, &block) # def sequence(name, type, options, &block)
|
|
131
|
+
options[:name] = name
|
|
132
|
+
proc = proc do |opts|
|
|
133
|
+
#{klass}.new(options.merge(opts)) # Sequence.new(options.merge(opts))
|
|
134
|
+
end
|
|
135
|
+
options[:content] ||= []
|
|
136
|
+
options[:content] += generate_content(&block)
|
|
137
|
+
push_element(BaseElem.new(name, proc, options[:content]))
|
|
138
|
+
end
|
|
139
|
+
EVAL
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @private
|
|
143
|
+
# @since 0.17.0
|
|
144
|
+
def generate_content
|
|
145
|
+
return [] unless block_given?
|
|
146
|
+
|
|
147
|
+
previous_elements = @elements
|
|
148
|
+
@elements = []
|
|
149
|
+
yield
|
|
150
|
+
content = @elements
|
|
151
|
+
@elements = previous_elements
|
|
152
|
+
content
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# @private
|
|
156
|
+
# @param accel_name [String,Symbol]
|
|
157
|
+
# @param klass [Class]
|
|
158
|
+
# @since 0.11.0
|
|
159
|
+
# @since 0.12.0 track source location on error (adfoster-r7)
|
|
160
|
+
def define_type_accel_of(accel_name, klass)
|
|
161
|
+
singleton_class.class_eval <<-EVAL, __FILE__, __LINE__ + 1
|
|
162
|
+
def #{accel_name}_of(name, type, options={}) # def sequence_of(name, type, options)
|
|
163
|
+
options[:name] = name
|
|
164
|
+
proc = proc do |opts|
|
|
165
|
+
#{klass}.new(type, options.merge(opts)) # SequenceOf.new(type, options.merge(opts))
|
|
166
|
+
end
|
|
167
|
+
push_element(BaseElem.new(name, proc, nil))
|
|
168
|
+
end
|
|
169
|
+
EVAL
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Define an accelarator to access a type in a model definition
|
|
173
|
+
# @param accel_name [String]
|
|
174
|
+
# @param klass [Class] class to instanciate
|
|
175
|
+
# @since 0.11.0
|
|
176
|
+
# @since 0.12.0 track source location on error (adfoster-r7)
|
|
177
|
+
def define_type_accel(accel_name, klass)
|
|
178
|
+
if klass <= Types::SequenceOf
|
|
179
|
+
define_type_accel_of(accel_name, klass)
|
|
180
|
+
elsif (klass <= Types::Sequence) || (klass <= Types::Choice)
|
|
181
|
+
define_type_accel_container(accel_name, klass)
|
|
182
|
+
else
|
|
183
|
+
define_type_accel_base(accel_name, klass)
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# @param name [Symbol,String] name of object in model
|
|
188
|
+
# @param options [Hash]
|
|
189
|
+
# @return [Elem]
|
|
190
|
+
# @note This method is named +objectid+ and not +object_id+ to not override
|
|
191
|
+
# +Object#object_id+.
|
|
192
|
+
# @see Types::ObjectId#initialize
|
|
193
|
+
def objectid(name, options={})
|
|
194
|
+
options[:name] = name
|
|
195
|
+
proc = proc { |opts| Types::ObjectId.new(options.merge(opts)) }
|
|
196
|
+
push_element(BaseElem.new(name, proc, nil))
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# @param name [Symbol,String] name of object in model
|
|
200
|
+
# @param options [Hash]
|
|
201
|
+
# @return [Elem]
|
|
202
|
+
# @see Types::Any#initialize
|
|
203
|
+
def any(name, options={})
|
|
204
|
+
options[:name] = name
|
|
205
|
+
proc = proc { |opts| Types::Any.new(options.merge(opts)) }
|
|
206
|
+
push_element(BaseElem.new(name, proc, nil))
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Give type name (aka class name)
|
|
210
|
+
# @return [String]
|
|
211
|
+
def type
|
|
212
|
+
return @type if defined? @type
|
|
213
|
+
|
|
214
|
+
@type = self.to_s.gsub(/.*::/, '')
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Parse a DER/BER encoded string
|
|
218
|
+
# @param str [String]
|
|
219
|
+
# @param ber [Boolean] accept BER encoding or not
|
|
220
|
+
# @return [Model]
|
|
221
|
+
# @raise [ASN1Error] error on parsing
|
|
222
|
+
def parse(str, ber: false)
|
|
223
|
+
model = new
|
|
224
|
+
model.parse!(str, ber: ber)
|
|
225
|
+
model
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|