rasn1 0.10.0 → 0.12.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.
data/lib/rasn1/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RASN1
4
- VERSION = '0.10.0'
4
+ VERSION = '0.12.0'
5
5
  end
@@ -0,0 +1,201 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+
5
+ module RASN1
6
+ # This class is used to wrap a {Types::Base} or {Model} instance to force its options.
7
+ #
8
+ # == Usage
9
+ # This class may be used to wrap another RASN1 object by 3 ways:
10
+ # * wrap an object to modify its options,
11
+ # * implicitly wrap an object (i.e. change its tag),
12
+ # * explicitly wrap an object (i.e wrap the object in another explicit ASN.1 tag)
13
+ #
14
+ # @example
15
+ # # object to wrap
16
+ # int = RASN1::Types::Integer.new(implicit: 1) # its tag is 0x81
17
+ # # simple wraper, change an option
18
+ # wrapper = RASN1::Wrapper.new(int, optional: true, default: 1)
19
+ # # implicit wrapper
20
+ # wrapper = RASN1::Wrapper.new(int, implicit: 3) # wrapped int tag is now 0x83
21
+ # # explicit wrapper
22
+ # wrapper = RASN1::Wrapper.new(int, explicit: 4) # int tag is always 0x81, but it is wrapped in a 0x84 tag
23
+ # @since 0.12.0
24
+ class Wrapper < SimpleDelegator
25
+ # @private Private class used to build/parse explicit wrappers
26
+ class ExplicitWrapper < Types::Base
27
+ ID = 0 # not used
28
+ ASN1_PC = 0 # not constructed
29
+
30
+ def self.type
31
+ ''
32
+ end
33
+
34
+ # @return [Boolean]
35
+ # @see Types::Base#can_build?
36
+ def can_build?
37
+ ok = super
38
+ return ok unless optional?
39
+
40
+ ok && @value.can_build?
41
+ end
42
+
43
+ private
44
+
45
+ def value_to_der
46
+ @value.is_a?(String) ? @value : @value.to_der
47
+ end
48
+
49
+ def inspect_value
50
+ ''
51
+ end
52
+ end
53
+
54
+ # @param [Types::Base,Model] element element to wrap
55
+ # @param [Hash] options
56
+ def initialize(element, options={})
57
+ opts = explicit_implicit(options)
58
+
59
+ if explicit?
60
+ generate_explicit_wrapper(opts)
61
+ element.options = element.options.merge(generate_explicit_wrapper_options(opts))
62
+ @options = opts
63
+ else
64
+ opts[:value] = element.value
65
+ element.options = element.options.merge(opts)
66
+ @options = {}
67
+ end
68
+ raise RASN1::Error, 'Cannot be implicit and explicit' if explicit? && implicit?
69
+
70
+ super(element)
71
+ end
72
+
73
+ def explicit_implicit(options)
74
+ opts = options.dup
75
+ @explicit = opts.delete(:explicit)
76
+ @implicit = opts.delete(:implicit)
77
+ opts
78
+ end
79
+
80
+ def generate_explicit_wrapper(options)
81
+ # ExplicitWrapper is a hand-made explicit tag, but we have to use its implicit option
82
+ # to force its tag value.
83
+ @explicit_wrapper = ExplicitWrapper.new(options.merge(implicit: @explicit))
84
+ end
85
+
86
+ def generate_explicit_wrapper_options(options)
87
+ new_opts = {}
88
+ new_opts[:default] = options[:default] if options.key?(:default)
89
+ new_opts[:optional] = options[:optional] if options.key?(:optional)
90
+ new_opts
91
+ end
92
+
93
+ # Say if wrapper is an explicit one (i.e. add tag and length to its element)
94
+ # @return [Boolean]
95
+ def explicit?
96
+ !!@explicit
97
+ end
98
+
99
+ # Say if wrapper is an implicit one (i.e. change tag of its element)
100
+ # @return [Boolean]
101
+ def implicit?
102
+ !!@implicit
103
+ end
104
+
105
+ # Convert wrapper and its element to a DER string
106
+ # @return [String]
107
+ def to_der
108
+ if implicit?
109
+ el = generate_implicit_element
110
+ el.to_der
111
+ elsif explicit?
112
+ @explicit_wrapper.value = element
113
+ @explicit_wrapper.to_der
114
+ else
115
+ element.to_der
116
+ end
117
+ end
118
+
119
+ # Parse a DER string. This method updates object.
120
+ # @param [String] der DER string
121
+ # @param [Boolean] ber if +true+, accept BER encoding
122
+ # @return [Integer] total number of parsed bytes
123
+ # @raise [ASN1Error] error on parsing
124
+ def parse!(der, ber: false)
125
+ if implicit?
126
+ el = generate_implicit_element
127
+ parsed = el.parse!(der, ber: ber)
128
+ element.value = el.value
129
+ parsed
130
+ elsif explicit?
131
+ parsed = @explicit_wrapper.parse!(der, ber: ber)
132
+ element.parse!(@explicit_wrapper.value, ber: ber) if parsed.positive?
133
+ parsed
134
+ else
135
+ element.parse!(der, ber: ber)
136
+ end
137
+ end
138
+
139
+ def value?
140
+ if explicit?
141
+ @explicit_wrapper.value?
142
+ else
143
+ __getobj__.value?
144
+ end
145
+ end
146
+
147
+ # Return Wrapped element
148
+ # @return [Types::Base,Model]
149
+ def element
150
+ __getobj__
151
+ end
152
+
153
+ # @return [::Integer]
154
+ def id
155
+ if implicit?
156
+ @implicit
157
+ elsif explicit?
158
+ @explicit
159
+ else
160
+ element.id
161
+ end
162
+ end
163
+
164
+ # @return [Symbol]
165
+ def asn1_class
166
+ return element.asn1_class unless @options.key?(:class)
167
+
168
+ @options[:class]
169
+ end
170
+
171
+ # @return [Boolean]
172
+ def constructed?
173
+ return element.constructed? unless @options.key?(:constructed)
174
+
175
+ @options[:constructed]
176
+ end
177
+
178
+ # @return [Boolean]
179
+ def primitive?
180
+ !constructed?
181
+ end
182
+
183
+ def inspect(level=0)
184
+ return super(level) unless explicit?
185
+
186
+ @explicit_wrapper.inspect(level) << ' ' << super(level)
187
+ end
188
+
189
+ private
190
+
191
+ def generate_implicit_element
192
+ el = element.dup
193
+ if el.explicit?
194
+ el.options = el.options.merge(explicit: @implicit)
195
+ elsif el.implicit?
196
+ el.options = el.options.merge(implicit: @implicit)
197
+ end
198
+ el
199
+ end
200
+ end
201
+ end
data/lib/rasn1.rb CHANGED
@@ -1,36 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rasn1/version'
4
- require 'rasn1/types'
5
- require 'rasn1/model'
3
+ require_relative 'rasn1/version'
4
+ require_relative 'rasn1/errors'
5
+ require_relative 'rasn1/types'
6
+ require_relative 'rasn1/model'
7
+ require_relative 'rasn1/wrapper'
6
8
 
7
9
  # Rasn1 is a pure ruby library to parse, decode and encode ASN.1 data.
8
10
  # @author Sylvain Daubert
9
11
  module RASN1
10
- # Base error class
11
- class Error < StandardError; end
12
-
13
- # ASN.1 encoding/decoding error
14
- class ASN1Error < Error; end
15
-
16
- # ASN.1 class error
17
- class ClassError < Error
18
- # @return [String]
19
- def message
20
- "Tag class should be a symbol among: #{Types::Base::CLASSES.keys.join(', ')}"
21
- end
22
- end
23
-
24
- # Enumerated error
25
- class EnumeratedError < Error; end
26
-
27
- # CHOICE error: #chosen not set
28
- class ChoiceError < RASN1::Error
29
- def message
30
- "CHOICE #{@name}: #chosen not set"
31
- end
32
- end
33
-
34
12
  # Parse a DER/BER string without checking a model
35
13
  # @note If you want to check ASN.1 grammary, you should define a {Model}
36
14
  # and use {Model#parse}.
metadata CHANGED
@@ -1,57 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rasn1
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.12.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: 2022-03-11 00:00:00.000000000 Z
11
+ date: 2022-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rake
14
+ name: strptime
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '12.3'
20
- type: :development
19
+ version: 0.2.5
20
+ type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '12.3'
27
- - !ruby/object:Gem::Dependency
28
- name: rspec
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '3.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '3.0'
41
- - !ruby/object:Gem::Dependency
42
- name: yard
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.9'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '0.9'
26
+ version: 0.2.5
55
27
  description: |
56
28
  RASN1 is a pure ruby ASN.1 library. It may encode and decode DER and BER
57
29
  encodings.
@@ -66,13 +38,16 @@ files:
66
38
  - LICENSE
67
39
  - README.md
68
40
  - lib/rasn1.rb
41
+ - lib/rasn1/errors.rb
69
42
  - lib/rasn1/model.rb
70
43
  - lib/rasn1/types.rb
71
44
  - lib/rasn1/types/any.rb
72
45
  - lib/rasn1/types/base.rb
73
46
  - lib/rasn1/types/bit_string.rb
47
+ - lib/rasn1/types/bmp_string.rb
74
48
  - lib/rasn1/types/boolean.rb
75
49
  - lib/rasn1/types/choice.rb
50
+ - lib/rasn1/types/constrained.rb
76
51
  - lib/rasn1/types/constructed.rb
77
52
  - lib/rasn1/types/enumerated.rb
78
53
  - lib/rasn1/types/generalized_time.rb
@@ -92,6 +67,7 @@ files:
92
67
  - lib/rasn1/types/utf8_string.rb
93
68
  - lib/rasn1/types/visible_string.rb
94
69
  - lib/rasn1/version.rb
70
+ - lib/rasn1/wrapper.rb
95
71
  homepage: https://github.com/sdaubert/rasn1
96
72
  licenses:
97
73
  - MIT