rasn1 0.8.0 → 0.9.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 +0 -1
- data/lib/rasn1/model.rb +107 -67
- data/lib/rasn1/types/any.rb +26 -15
- data/lib/rasn1/types/base.rb +100 -78
- data/lib/rasn1/types/bit_string.rb +30 -28
- data/lib/rasn1/types/boolean.rb +5 -0
- data/lib/rasn1/types/choice.rb +4 -4
- data/lib/rasn1/types/constructed.rb +0 -2
- data/lib/rasn1/types/enumerated.rb +6 -13
- data/lib/rasn1/types/generalized_time.rb +99 -56
- data/lib/rasn1/types/ia5string.rb +1 -1
- data/lib/rasn1/types/integer.rb +76 -55
- data/lib/rasn1/types/null.rb +3 -2
- data/lib/rasn1/types/object_id.rb +2 -2
- data/lib/rasn1/types/sequence.rb +22 -5
- data/lib/rasn1/types/sequence_of.rb +43 -31
- data/lib/rasn1/types/utc_time.rb +1 -1
- data/lib/rasn1/types/utf8_string.rb +1 -1
- data/lib/rasn1/types.rb +16 -15
- data/lib/rasn1/version.rb +1 -1
- data/lib/rasn1.rb +1 -1
- metadata +4 -5
data/lib/rasn1/types/integer.rb
CHANGED
@@ -11,97 +11,117 @@ module RASN1
|
|
11
11
|
# Integer id value
|
12
12
|
ID = 2
|
13
13
|
|
14
|
-
# @
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# @raise [EnumeratedError] +:default+ value is unknown when +:enum+ key is present
|
18
|
-
# @overload initialize(value, options={})
|
19
|
-
# @param [Object] value value to set for this ASN.1 object
|
20
|
-
# @option options [Hash] :enum enumeration hash. Keys are names, and values
|
21
|
-
# are integers. This key is mandatory.
|
22
|
-
# @raise [EnumeratedError] +:default+ value is unknown when +:enum+ key is present
|
14
|
+
# @option options [Hash] :enum enumeration hash. Keys are names, and values
|
15
|
+
# are integers.
|
16
|
+
# @raise [EnumeratedError] +:default+ value is unknown when +:enum+ key is present
|
23
17
|
# @see Base#initialize common options to all ASN.1 types
|
24
|
-
def initialize(
|
18
|
+
def initialize(options={})
|
25
19
|
super
|
26
|
-
@
|
27
|
-
|
28
|
-
return if @enum.nil?
|
29
|
-
|
30
|
-
# To ensure @value has the correct type
|
31
|
-
self.value = @value
|
32
|
-
|
33
|
-
case @default
|
34
|
-
when String, Symbol
|
35
|
-
raise EnumeratedError, "#{@name}: unknwon enumerated default value #@{default}" unless @enum.key? @default
|
36
|
-
when ::Integer
|
37
|
-
raise EnumeratedError, "#{@name}: default value #@{default} not in enumeration" unless @enum.value? @default
|
38
|
-
|
39
|
-
@default = @enum.key(@default)
|
40
|
-
when nil
|
41
|
-
else
|
42
|
-
raise TypeError, "#{@name}: #{@default.class} not handled as default value"
|
43
|
-
end
|
20
|
+
initialize_enum(@options[:enum])
|
44
21
|
end
|
45
22
|
|
46
23
|
# @param [Integer,String,Symbol,nil] v
|
47
|
-
# @return [
|
24
|
+
# @return [void]
|
48
25
|
def value=(val)
|
26
|
+
@no_value = false
|
49
27
|
case val
|
50
28
|
when String, Symbol
|
51
|
-
|
52
|
-
raise EnumeratedError, "#{@name}: unknwon enumerated value #{val}" unless @enum.key? val
|
53
|
-
|
54
|
-
@value = val
|
29
|
+
value_from_string_or_symbol(val)
|
55
30
|
when ::Integer
|
56
|
-
|
57
|
-
@value = val
|
58
|
-
elsif @enum.value? val
|
59
|
-
@value = @enum.key(val)
|
60
|
-
else
|
61
|
-
raise EnumeratedError, "#{@name}: #{val} not in enumeration"
|
62
|
-
end
|
31
|
+
value_from_integer(val)
|
63
32
|
when nil
|
64
|
-
@
|
33
|
+
@no_value = true
|
34
|
+
@value = void_value
|
65
35
|
else
|
66
36
|
raise EnumeratedError, "#{@name}: not in enumeration"
|
67
37
|
end
|
68
38
|
end
|
69
39
|
|
40
|
+
# @return [Integer]
|
41
|
+
def void_value
|
42
|
+
0
|
43
|
+
end
|
44
|
+
|
70
45
|
# Integer value
|
71
46
|
# @return [Integer]
|
72
47
|
def to_i
|
73
|
-
if @enum.
|
74
|
-
@value
|
48
|
+
if @enum.empty?
|
49
|
+
value? ? @value : @default || 0
|
75
50
|
else
|
76
|
-
@enum[@value
|
51
|
+
@enum[value? ? @value : @default] || 0
|
77
52
|
end
|
78
53
|
end
|
79
54
|
|
80
55
|
private
|
81
56
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
57
|
+
def initialize_enum(enum)
|
58
|
+
@enum = enum || {}
|
59
|
+
return if @enum.empty?
|
60
|
+
|
61
|
+
# To ensure @value has the correct type
|
62
|
+
self.value = @value if value?
|
63
|
+
|
64
|
+
check_enum_default
|
65
|
+
end
|
66
|
+
|
67
|
+
def check_enum_default
|
68
|
+
case @default
|
69
|
+
when String, Symbol
|
70
|
+
raise EnumeratedError, "#{@name}: unknwon enumerated default value #@{default}" unless @enum.key?(@default)
|
71
|
+
when ::Integer
|
72
|
+
raise EnumeratedError, "#{@name}: default value #@{default} not in enumeration" unless @enum.value?(@default)
|
73
|
+
|
74
|
+
@default = @enum.key(@default)
|
75
|
+
when nil
|
76
|
+
else
|
77
|
+
raise TypeError, "#{@name}: #{@default.class} not handled as default value"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def value_from_string_or_symbol(val)
|
82
|
+
raise EnumeratedError, "#{@name} has no :enum" if @enum.empty?
|
83
|
+
raise EnumeratedError, "#{@name}: unknwon enumerated value #{val}" unless @enum.key? val
|
84
|
+
|
85
|
+
@value = val
|
86
|
+
end
|
87
|
+
|
88
|
+
def value_from_integer(val)
|
89
|
+
if @enum.empty?
|
90
|
+
@value = val
|
91
|
+
elsif @enum.value? val
|
92
|
+
@value = @enum.key(val)
|
93
|
+
else
|
94
|
+
raise EnumeratedError, "#{@name}: #{val} not in enumeration"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def int_value_to_der(value)
|
99
|
+
size = compute_size(value)
|
100
|
+
comp_value = value >= 0 ? value : (~(-value) + 1) & ((1 << (size * 8)) - 1)
|
87
101
|
ary = comp_value.digits(256)
|
88
102
|
# v is > 0 and its MSBit is 1. Add a 0 byte to mark it as positive
|
89
|
-
ary << 0 if
|
103
|
+
ary << 0 if value.positive? && (value >> (size * 8 - 1) == 1)
|
90
104
|
ary.reverse.pack('C*')
|
91
105
|
end
|
92
106
|
|
107
|
+
def compute_size(value)
|
108
|
+
size = value.bit_length / 8 + ((value.bit_length % 8).positive? ? 1 : 0)
|
109
|
+
size = 1 if size.zero?
|
110
|
+
size
|
111
|
+
end
|
112
|
+
|
93
113
|
def value_to_der
|
94
114
|
case @value
|
95
115
|
when String, Symbol
|
96
|
-
int_value_to_der
|
116
|
+
int_value_to_der(@enum[@value])
|
97
117
|
when ::Integer
|
98
|
-
int_value_to_der
|
118
|
+
int_value_to_der(@value)
|
99
119
|
else
|
100
120
|
raise TypeError, "#{@name}: #{@value.class} not handled"
|
101
121
|
end
|
102
122
|
end
|
103
123
|
|
104
|
-
def der_to_int_value(der, ber: false)
|
124
|
+
def der_to_int_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
|
105
125
|
ary = der.unpack('C*')
|
106
126
|
v = ary.reduce(0) { |len, b| (len << 8) | b }
|
107
127
|
v = -((~v & ((1 << v.bit_length) - 1)) + 1) if ary[0] & 0x80 == 0x80
|
@@ -110,10 +130,11 @@ module RASN1
|
|
110
130
|
|
111
131
|
def der_to_value(der, ber: false)
|
112
132
|
@value = der_to_int_value(der, ber: ber)
|
113
|
-
return if @enum.
|
133
|
+
return if @enum.empty?
|
114
134
|
|
135
|
+
int_value = @value
|
115
136
|
@value = @enum.key(@value)
|
116
|
-
raise EnumeratedError, "#{@name}: value #{
|
137
|
+
raise EnumeratedError, "#{@name}: value #{int_value} not in enumeration" unless value?
|
117
138
|
end
|
118
139
|
|
119
140
|
def explicit_type
|
data/lib/rasn1/types/null.rb
CHANGED
@@ -21,10 +21,11 @@ module RASN1
|
|
21
21
|
''
|
22
22
|
end
|
23
23
|
|
24
|
-
def der_to_value(der, ber: false)
|
24
|
+
def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
|
25
25
|
raise ASN1Error, 'NULL should not have content!' if der.length.positive?
|
26
26
|
|
27
|
-
@
|
27
|
+
@no_value = true
|
28
|
+
@value = void_value
|
28
29
|
end
|
29
30
|
end
|
30
31
|
end
|
@@ -11,7 +11,7 @@ module RASN1
|
|
11
11
|
private
|
12
12
|
|
13
13
|
def value_to_der
|
14
|
-
ids = @value.split('.').map!(&:to_i)
|
14
|
+
ids = @value.to_s.split('.').map!(&:to_i)
|
15
15
|
|
16
16
|
raise ASN1Error, "OBJECT ID #{@name}: first subidentifier should be less than 3" if ids[0] > 2
|
17
17
|
raise ASN1Error, "OBJECT ID #{@name}: second subidentifier should be less than 40" if (ids[0] < 2) && (ids[1] > 39)
|
@@ -25,7 +25,7 @@ module RASN1
|
|
25
25
|
ids.flatten.pack('C*')
|
26
26
|
end
|
27
27
|
|
28
|
-
def der_to_value(der, ber: false)
|
28
|
+
def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
|
29
29
|
bytes = der.unpack('C*')
|
30
30
|
|
31
31
|
ids = []
|
data/lib/rasn1/types/sequence.rb
CHANGED
@@ -30,23 +30,36 @@ module RASN1
|
|
30
30
|
ID = 0x10
|
31
31
|
|
32
32
|
# @see Base#initialize
|
33
|
-
def initialize(
|
33
|
+
def initialize(options={})
|
34
34
|
super
|
35
|
+
@no_value = false
|
35
36
|
@value ||= []
|
36
37
|
end
|
37
38
|
|
38
39
|
def initialize_copy(other)
|
39
40
|
super
|
40
|
-
@value = @value
|
41
|
+
@value = case @value
|
42
|
+
when Array
|
43
|
+
@value.map(&:dup)
|
44
|
+
else
|
45
|
+
@value.dup
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Array]
|
50
|
+
def void_value
|
51
|
+
[]
|
41
52
|
end
|
42
53
|
|
43
54
|
# Get element at index +idx+, or element of name +name+
|
44
55
|
# @param [Integer, String, Symbol] idx_or_name
|
45
|
-
# @return [Object]
|
56
|
+
# @return [Object,nil]
|
46
57
|
def [](idx_or_name)
|
58
|
+
return unless @value.is_a?(Array)
|
59
|
+
|
47
60
|
case idx_or_name
|
48
61
|
when Integer
|
49
|
-
@value[
|
62
|
+
@value[idx_or_name.to_i]
|
50
63
|
when String, Symbol
|
51
64
|
@value.find { |elt| elt.name == idx_or_name }
|
52
65
|
end
|
@@ -63,7 +76,7 @@ module RASN1
|
|
63
76
|
end
|
64
77
|
end
|
65
78
|
|
66
|
-
def der_to_value(der, ber: false)
|
79
|
+
def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
|
67
80
|
if @value.is_a?(Array) && !@value.empty?
|
68
81
|
nb_bytes = 0
|
69
82
|
@value.each do |element|
|
@@ -74,6 +87,10 @@ module RASN1
|
|
74
87
|
der.length
|
75
88
|
end
|
76
89
|
end
|
90
|
+
|
91
|
+
def explicit_type
|
92
|
+
self.class.new(value: @value)
|
93
|
+
end
|
77
94
|
end
|
78
95
|
end
|
79
96
|
end
|
@@ -64,7 +64,7 @@ module RASN1
|
|
64
64
|
def initialize(of_type, options={})
|
65
65
|
super(options)
|
66
66
|
@of_type = of_type
|
67
|
-
@
|
67
|
+
@no_value = false
|
68
68
|
end
|
69
69
|
|
70
70
|
def initialize_copy(other)
|
@@ -73,33 +73,18 @@ module RASN1
|
|
73
73
|
@value = @value.map(&:dup)
|
74
74
|
end
|
75
75
|
|
76
|
+
# @return [Array]
|
77
|
+
def void_value
|
78
|
+
[]
|
79
|
+
end
|
80
|
+
|
76
81
|
# Add an item to SEQUENCE OF
|
77
82
|
# @param [Array,Hash, Model]
|
78
83
|
def <<(obj)
|
79
|
-
if of_type_class < Primitive
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
elsif composed_of_type?
|
84
|
-
raise ASN1Error, 'object to add should be an Array' unless obj.is_a?(Array)
|
85
|
-
|
86
|
-
new_value = of_type_class.new
|
87
|
-
@of_type.value.each_with_index do |type, i|
|
88
|
-
type2 = type.dup
|
89
|
-
type2.value = obj[i]
|
90
|
-
new_value.value << type2
|
91
|
-
end
|
92
|
-
@value << new_value
|
93
|
-
elsif of_type_class < Model
|
94
|
-
case obj
|
95
|
-
when Hash
|
96
|
-
@value << @of_type.new(obj)
|
97
|
-
when of_type_class
|
98
|
-
@value << obj
|
99
|
-
else
|
100
|
-
raise ASN1Error, "object to add should be a #{of_type_class} or a Hash"
|
101
|
-
end
|
102
|
-
end
|
84
|
+
return push_array_of_primitive(obj) if of_type_class < Primitive
|
85
|
+
return push_composed_array(obj) if composed_of_type?
|
86
|
+
|
87
|
+
push_model(obj)
|
103
88
|
end
|
104
89
|
|
105
90
|
# Get element of index +idx+
|
@@ -140,24 +125,22 @@ module RASN1
|
|
140
125
|
end
|
141
126
|
|
142
127
|
def composed_of_type?
|
143
|
-
[Sequence, Set].include?
|
128
|
+
!@of_type.is_a?(Class) && [Sequence, Set].include?(of_type_class)
|
144
129
|
end
|
145
130
|
|
146
131
|
def value_to_der
|
147
132
|
@value.map(&:to_der).join
|
148
133
|
end
|
149
134
|
|
150
|
-
def der_to_value(der, ber: false)
|
135
|
+
def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
|
151
136
|
@value = []
|
152
137
|
nb_bytes = 0
|
153
138
|
|
154
139
|
while nb_bytes < der.length
|
155
|
-
type = if composed_of_type?
|
140
|
+
type = if composed_of_type? && !@of_type.is_a?(Class)
|
156
141
|
@of_type.dup
|
157
|
-
elsif of_type_class < Model
|
158
|
-
of_type_class.new
|
159
142
|
else
|
160
|
-
of_type_class.new
|
143
|
+
of_type_class.new
|
161
144
|
end
|
162
145
|
nb_bytes += type.parse!(der[nb_bytes, der.length])
|
163
146
|
@value << type
|
@@ -167,6 +150,35 @@ module RASN1
|
|
167
150
|
def explicit_type
|
168
151
|
self.class.new(self.of_type)
|
169
152
|
end
|
153
|
+
|
154
|
+
def push_array_of_primitive(obj)
|
155
|
+
raise ASN1Error, 'object to add should be an Array' unless obj.is_a?(Array)
|
156
|
+
|
157
|
+
@value += obj.map { |item| of_type_class.new(value: item) }
|
158
|
+
end
|
159
|
+
|
160
|
+
def push_composed_array(obj)
|
161
|
+
raise ASN1Error, 'object to add should be an Array' unless obj.is_a?(Array)
|
162
|
+
|
163
|
+
new_value = of_type_class.new
|
164
|
+
@of_type.value.each_with_index do |type, i|
|
165
|
+
type2 = type.dup
|
166
|
+
type2.value = obj[i]
|
167
|
+
new_value.value << type2
|
168
|
+
end
|
169
|
+
@value << new_value
|
170
|
+
end
|
171
|
+
|
172
|
+
def push_model(obj)
|
173
|
+
case obj
|
174
|
+
when Hash
|
175
|
+
@value << of_type_class.new(obj)
|
176
|
+
when of_type_class
|
177
|
+
@value << obj
|
178
|
+
else
|
179
|
+
raise ASN1Error, "object to add should be a #{of_type_class} or a Hash"
|
180
|
+
end
|
181
|
+
end
|
170
182
|
end
|
171
183
|
end
|
172
184
|
end
|
data/lib/rasn1/types/utc_time.rb
CHANGED
data/lib/rasn1/types.rb
CHANGED
@@ -24,15 +24,16 @@ module RASN1
|
|
24
24
|
# @return [Array] Return ASN.1 class as Symbol, contructed/primitive as Symbol,
|
25
25
|
# ID and size of identifier octets
|
26
26
|
def self.decode_identifier_octets(der)
|
27
|
-
first_octet = der
|
27
|
+
first_octet = der.unpack1('C').to_i
|
28
28
|
asn1_class = Types::Base::CLASSES.key(first_octet & Types::Base::CLASS_MASK)
|
29
29
|
pc = (first_octet & Types::Constructed::ASN1_PC).positive? ? :constructed : :primitive
|
30
30
|
id = first_octet & Types::Base::MULTI_OCTETS_ID
|
31
31
|
|
32
32
|
size = if id == Types::Base::MULTI_OCTETS_ID
|
33
33
|
id = 0
|
34
|
-
|
35
|
-
|
34
|
+
der.bytes.each_with_index do |octet, i|
|
35
|
+
next if i.zero?
|
36
|
+
|
36
37
|
id = (id << 7) | (octet & 0x7f)
|
37
38
|
break i + 1 if (octet & 0x80).zero?
|
38
39
|
end
|
@@ -50,18 +51,7 @@ module RASN1
|
|
50
51
|
# @raise [ASN1Error] +tag+ is out of range
|
51
52
|
def self.id2type(der)
|
52
53
|
# Define a cache for well-known ASN.1 types
|
53
|
-
unless defined? @id2types
|
54
|
-
constructed = self.constructed - [Types::SequenceOf, Types::SetOf]
|
55
|
-
primitives = self.primitives - [Types::Enumerated]
|
56
|
-
ary = (primitives + constructed).map do |type|
|
57
|
-
next unless type.const_defined? :ID
|
58
|
-
|
59
|
-
[type::ID, type]
|
60
|
-
end
|
61
|
-
@id2types = Hash[ary]
|
62
|
-
@id2types.default = Types::Base
|
63
|
-
@id2types.freeze
|
64
|
-
end
|
54
|
+
self.generate_id2type_cache unless defined? @id2types
|
65
55
|
|
66
56
|
asn1class, pc, id, = self.decode_identifier_octets(der)
|
67
57
|
# cache_id: check versus class and 5 LSB bits
|
@@ -72,6 +62,17 @@ module RASN1
|
|
72
62
|
options[:tag_value] = id if klass == Types::Base
|
73
63
|
klass.new(options)
|
74
64
|
end
|
65
|
+
|
66
|
+
# @private Generate cache for {.id2type}
|
67
|
+
def self.generate_id2type_cache
|
68
|
+
constructed = self.constructed - [Types::SequenceOf, Types::SetOf]
|
69
|
+
primitives = self.primitives - [Types::Enumerated]
|
70
|
+
ary = (primitives + constructed).select { |type| type.const_defined? :ID }
|
71
|
+
.map { |type| [type::ID, type] }
|
72
|
+
@id2types = ary.to_h
|
73
|
+
@id2types.default = Types::Base
|
74
|
+
@id2types.freeze
|
75
|
+
end
|
75
76
|
end
|
76
77
|
end
|
77
78
|
|
data/lib/rasn1/version.rb
CHANGED
data/lib/rasn1.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.9.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:
|
11
|
+
date: 2021-12-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -114,15 +114,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
114
114
|
requirements:
|
115
115
|
- - ">="
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 2.
|
117
|
+
version: 2.5.0
|
118
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
119
|
requirements:
|
120
120
|
- - ">="
|
121
121
|
- !ruby/object:Gem::Version
|
122
122
|
version: '0'
|
123
123
|
requirements: []
|
124
|
-
|
125
|
-
rubygems_version: 2.7.6.2
|
124
|
+
rubygems_version: 3.2.5
|
126
125
|
signing_key:
|
127
126
|
specification_version: 4
|
128
127
|
summary: Ruby ASN.1 library
|