rasn1 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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