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.
@@ -22,7 +22,7 @@ module RASN1
22
22
 
23
23
  def der_to_value(der, ber: false)
24
24
  super
25
- @value.force_encoding('US-ASCII')
25
+ @value.to_s.force_encoding('US-ASCII')
26
26
  end
27
27
  end
28
28
  end
@@ -11,97 +11,117 @@ module RASN1
11
11
  # Integer id value
12
12
  ID = 2
13
13
 
14
- # @overload initialize(options={})
15
- # @option options [Hash] :enum enumeration hash. Keys are names, and values
16
- # are integers.
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(value_or_options={}, options={})
18
+ def initialize(options={})
25
19
  super
26
- @enum = @options[:enum]
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 [String,Symbol,nil]
24
+ # @return [void]
48
25
  def value=(val)
26
+ @no_value = false
49
27
  case val
50
28
  when String, Symbol
51
- raise EnumeratedError, "#{@name} has no :enum" if @enum.nil?
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
- if @enum.nil?
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
- @value = nil
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.nil?
74
- @value || @default || 0
48
+ if @enum.empty?
49
+ value? ? @value : @default || 0
75
50
  else
76
- @enum[@value || @default] || 0
51
+ @enum[value? ? @value : @default] || 0
77
52
  end
78
53
  end
79
54
 
80
55
  private
81
56
 
82
- def int_value_to_der(value=nil)
83
- v = value || @value
84
- size = v.bit_length / 8 + ((v.bit_length % 8).positive? ? 1 : 0)
85
- size = 1 if size.zero?
86
- comp_value = v >= 0 ? v : (~(-v) + 1) & ((1 << (size * 8)) - 1)
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 v.positive? && (v >> (size * 8 - 1) == 1)
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 @enum[@value]
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.nil?
133
+ return if @enum.empty?
114
134
 
135
+ int_value = @value
115
136
  @value = @enum.key(@value)
116
- raise EnumeratedError, "#{@name}: value #{v} not in enumeration" if @value.nil?
137
+ raise EnumeratedError, "#{@name}: value #{int_value} not in enumeration" unless value?
117
138
  end
118
139
 
119
140
  def explicit_type
@@ -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
- @value = nil
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 = []
@@ -30,23 +30,36 @@ module RASN1
30
30
  ID = 0x10
31
31
 
32
32
  # @see Base#initialize
33
- def initialize(value_or_options={}, options={})
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.map(&:dup)
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[idx]
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
- @value = []
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
- raise ASN1Error, 'object to add should be an Array' unless obj.is_a?(Array)
81
-
82
- @value += obj.map { |item| @of_type.new(item) }
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? of_type_class
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(:t)
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
@@ -33,7 +33,7 @@ module RASN1
33
33
  @value.getutc.strftime('%y%m%d%H%M%SZ')
34
34
  end
35
35
 
36
- def der_to_value(der, ber: false)
36
+ def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument
37
37
  format = case der.size
38
38
  when 11
39
39
  '%Y%m%d%H%MZ'
@@ -22,7 +22,7 @@ module RASN1
22
22
 
23
23
  def der_to_value(der, ber: false)
24
24
  super
25
- @value.force_encoding('UTF-8')
25
+ @value = der.force_encoding('UTF-8')
26
26
  end
27
27
  end
28
28
  end
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[0].unpack1('C')
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
- 1.upto(der.size - 1) do |i|
35
- octet = der[i].unpack1('C')
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RASN1
4
- VERSION = '0.8.0'
4
+ VERSION = '0.9.0'
5
5
  end
data/lib/rasn1.rb CHANGED
@@ -46,7 +46,7 @@ module RASN1
46
46
  until der.empty?
47
47
  type = Types.id2type(der)
48
48
  type.parse!(der, ber: ber)
49
- root = type if root.nil?
49
+ root ||= type
50
50
 
51
51
  if [Types::Sequence, Types::Set].include? type.class
52
52
  subder = type.value
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.8.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: 2020-12-04 00:00:00.000000000 Z
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.4.0
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
- rubyforge_project:
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