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.
- checksums.yaml +4 -4
- data/lib/rasn1/errors.rb +54 -0
- data/lib/rasn1/model.rb +251 -123
- data/lib/rasn1/types/any.rb +4 -0
- data/lib/rasn1/types/base.rb +47 -27
- data/lib/rasn1/types/bit_string.rb +11 -8
- data/lib/rasn1/types/bmp_string.rb +30 -0
- data/lib/rasn1/types/choice.rb +8 -10
- data/lib/rasn1/types/constrained.rb +55 -0
- data/lib/rasn1/types/constructed.rb +17 -1
- data/lib/rasn1/types/generalized_time.rb +29 -42
- data/lib/rasn1/types/ia5string.rb +2 -2
- data/lib/rasn1/types/integer.rb +2 -1
- data/lib/rasn1/types/null.rb +4 -0
- data/lib/rasn1/types/numeric_string.rb +1 -1
- data/lib/rasn1/types/printable_string.rb +1 -1
- data/lib/rasn1/types/sequence_of.rb +1 -1
- data/lib/rasn1/types/utc_time.rb +3 -7
- data/lib/rasn1/types/utf8_string.rb +2 -2
- data/lib/rasn1/types.rb +41 -6
- data/lib/rasn1/version.rb +1 -1
- data/lib/rasn1/wrapper.rb +201 -0
- data/lib/rasn1.rb +5 -27
- metadata +10 -34
data/lib/rasn1/version.rb
CHANGED
@@ -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
|
-
|
4
|
-
|
5
|
-
|
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.
|
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-
|
11
|
+
date: 2022-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: strptime
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
-
type: :
|
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:
|
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
|