rasn1 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,8 +5,8 @@ module RASN1
5
5
  # ASN.1 Bit String
6
6
  # @author Sylvain Daubert
7
7
  class BitString < Primitive
8
- # BitString tag value
9
- TAG = 0x03
8
+ # BitString id value
9
+ ID = 3
10
10
 
11
11
  # @param [Integer] bit_length
12
12
  # @return [Integer]
@@ -24,14 +24,12 @@ module RASN1
24
24
  # @see Base#initialize common options to all ASN.1 types
25
25
  def initialize(value_or_options={}, options={})
26
26
  super
27
- opts = value_or_options.is_a?(Hash) ? value_or_options : options
28
27
  if @default
29
- if opts[:bit_length].nil?
30
- raise ASN1Error, "TAG #{@name}: default bit length is not defined"
31
- end
32
- @default_bit_length = opts[:bit_length]
28
+ raise ASN1Error, "#{@name}: default bit length is not defined" if @options[:bit_length].nil?
29
+
30
+ @default_bit_length = @options[:bit_length]
33
31
  end
34
- @bit_length = opts[:bit_length]
32
+ @bit_length = @options[:bit_length]
35
33
  end
36
34
 
37
35
  # Get bit length
@@ -52,14 +50,14 @@ module RASN1
52
50
 
53
51
  private
54
52
 
55
- def build_tag?
53
+ def can_build?
56
54
  !(!@default.nil? && (@value.nil? || (@value == @default) &&
57
55
  (@bit_length == @default_bit_length))) &&
58
56
  !(optional? && @value.nil?)
59
57
  end
60
58
 
61
59
  def value_to_der
62
- raise ASN1Error, "TAG #{@name}: bit length is not set" if bit_length.nil?
60
+ raise ASN1Error, "#{@name}: bit length is not set" if bit_length.nil?
63
61
 
64
62
  @value << "\x00" while @value.length * 8 < @bit_length
65
63
  @value.force_encoding('BINARY')
@@ -73,7 +71,7 @@ module RASN1
73
71
  der = [unused, @value].pack('CA*')
74
72
 
75
73
  if unused.positive?
76
- last_byte = @value[-1].unpack('C').first
74
+ last_byte = @value[-1].unpack1('C')
77
75
  last_byte &= (0xff >> unused) << unused
78
76
  der[-1] = [last_byte].pack('C')
79
77
  end
@@ -5,8 +5,8 @@ module RASN1
5
5
  # ASN.1 Boolean
6
6
  # @author Sylvain Daubert
7
7
  class Boolean < Primitive
8
- # Boolean tag value
9
- TAG = 0x01
8
+ # Boolean id value
9
+ ID = 0x01
10
10
 
11
11
  # @private
12
12
  DER_TRUE = 0xff
@@ -22,7 +22,7 @@ module RASN1
22
22
  def der_to_value(der, ber: false)
23
23
  raise ASN1Error, "tag #{@name}: BOOLEAN should have a length of 1" unless der.size == 1
24
24
 
25
- bool = der.unpack('C').first
25
+ bool = der.unpack1('C')
26
26
  case bool
27
27
  when DER_FALSE
28
28
  @value = false
@@ -79,7 +79,7 @@ module RASN1
79
79
  @value.each_with_index do |element, i|
80
80
  begin
81
81
  @chosen = i
82
- nb_bytes = element.parse!(der)
82
+ nb_bytes = element.parse!(der, ber: ber)
83
83
  parsed = true
84
84
  return nb_bytes
85
85
  rescue ASN1Error
@@ -23,7 +23,8 @@ module RASN1
23
23
 
24
24
  str << "#{item.inspect(level)}\n"
25
25
  else
26
- str << ' ' * level + item.inspect + "\n"
26
+ str << ' ' * level
27
+ str << "#{item.inspect}\n"
27
28
  end
28
29
  end
29
30
  str
@@ -22,8 +22,8 @@ module RASN1
22
22
  # @!attribute enum
23
23
  # @return [Hash]
24
24
 
25
- # Enumerated tag value
26
- TAG = 0x0a
25
+ # Enumerated id value
26
+ ID = 0x0a
27
27
 
28
28
  # @overload initialize(options={})
29
29
  # @option options [Hash] :enum enumeration hash. Keys are names, and values
@@ -21,8 +21,8 @@ module RASN1
21
21
  # second are supported.
22
22
  # @author Sylvain Daubert
23
23
  class GeneralizedTime < Primitive
24
- # GeneralizedTime tag value
25
- TAG = 24
24
+ # GeneralizedTime id value
25
+ ID = 24
26
26
 
27
27
  # Get ASN.1 type
28
28
  # @return [String]
@@ -5,8 +5,8 @@ module RASN1
5
5
  # ASN.1 IA5 String
6
6
  # @author Sylvain Daubert
7
7
  class IA5String < OctetString
8
- # IA5String tag value
9
- TAG = 22
8
+ # IA5String id value
9
+ ID = 22
10
10
 
11
11
  # Get ASN.1 type
12
12
  # @return [String]
@@ -8,8 +8,8 @@ module RASN1
8
8
  # @return [Hash,nil]
9
9
  attr_reader :enum
10
10
 
11
- # Integer tag value
12
- TAG = 0x02
11
+ # Integer id value
12
+ ID = 2
13
13
 
14
14
  # @overload initialize(options={})
15
15
  # @option options [Hash] :enum enumeration hash. Keys are names, and values
@@ -23,8 +23,7 @@ module RASN1
23
23
  # @see Base#initialize common options to all ASN.1 types
24
24
  def initialize(value_or_options={}, options={})
25
25
  super
26
- opts = value_or_options.is_a?(Hash) ? value_or_options : options
27
- @enum = opts[:enum]
26
+ @enum = @options[:enum]
28
27
 
29
28
  return if @enum.nil?
30
29
 
@@ -33,44 +32,38 @@ module RASN1
33
32
 
34
33
  case @default
35
34
  when String, Symbol
36
- unless @enum.key? @default
37
- raise EnumeratedError, "TAG #{@name}: unknwon enumerated default value #@{default}"
38
- end
35
+ raise EnumeratedError, "#{@name}: unknwon enumerated default value #@{default}" unless @enum.key? @default
39
36
  when ::Integer
40
- if @enum.value? @default
41
- @default = @enum.key(@default)
42
- else
43
- raise EnumeratedError, "TAG #{@name}: default value #@{default} not in enumeration"
44
- end
37
+ raise EnumeratedError, "#{@name}: default value #@{default} not in enumeration" unless @enum.value? @default
38
+
39
+ @default = @enum.key(@default)
45
40
  when nil
46
41
  else
47
- raise TypeError, "TAG #{@name}: #{@default.class} not handled as default value"
42
+ raise TypeError, "#{@name}: #{@default.class} not handled as default value"
48
43
  end
49
44
  end
50
45
 
51
46
  # @param [Integer,String,Symbol,nil] v
52
47
  # @return [String,Symbol,nil]
53
- def value=(v)
54
- case v
55
- when String,Symbol
56
- raise EnumeratedError, "TAG #{@name} has no :enum" if @enum.nil?
48
+ def value=(val)
49
+ case val
50
+ 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
57
53
 
58
- unless @enum.key? v
59
- raise EnumeratedError, "TAG #{@name}: unknwon enumerated value #{v}"
60
- end
61
- @value = v
54
+ @value = val
62
55
  when ::Integer
63
56
  if @enum.nil?
64
- @value = v
65
- elsif @enum.value? v
66
- @value = @enum.key(v)
57
+ @value = val
58
+ elsif @enum.value? val
59
+ @value = @enum.key(val)
67
60
  else
68
- raise EnumeratedError, "TAG #{@name}: #{v} not in enumeration"
61
+ raise EnumeratedError, "#{@name}: #{val} not in enumeration"
69
62
  end
70
63
  when nil
71
64
  @value = nil
72
65
  else
73
- raise EnumeratedError, "TAG #{@name}: not in enumeration"
66
+ raise EnumeratedError, "#{@name}: not in enumeration"
74
67
  end
75
68
  end
76
69
 
@@ -90,16 +83,10 @@ module RASN1
90
83
  v = value || @value
91
84
  size = v.bit_length / 8 + ((v.bit_length % 8).positive? ? 1 : 0)
92
85
  size = 1 if size.zero?
93
- comp_value = if v.positive?
94
- # If MSB is 1, increment size to set initial octet
95
- # to 0 to amrk it as a positive integer
96
- size += 1 if v >> (size * 8 - 1) == 1
97
- v
98
- else
99
- ~v.abs + 1
100
- end
101
- ary = []
102
- size.times { ary << (comp_value & 0xff); comp_value >>= 8 }
86
+ comp_value = v >= 0 ? v : (~(-v) + 1) & ((1 << (size * 8)) - 1)
87
+ ary = comp_value.digits(256)
88
+ # 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
90
  ary.reverse.pack('C*')
104
91
  end
105
92
 
@@ -110,16 +97,14 @@ module RASN1
110
97
  when ::Integer
111
98
  int_value_to_der
112
99
  else
113
- raise TypeError, "TAG #{@name}: #{@value.class} not handled"
100
+ raise TypeError, "#{@name}: #{@value.class} not handled"
114
101
  end
115
102
  end
116
103
 
117
104
  def der_to_int_value(der, ber: false)
118
105
  ary = der.unpack('C*')
119
106
  v = ary.reduce(0) { |len, b| (len << 8) | b }
120
- if ary[0] & 0x80 == 0x80
121
- v = -((~v & ((1 << v.bit_length) - 1)) + 1)
122
- end
107
+ v = -((~v & ((1 << v.bit_length) - 1)) + 1) if ary[0] & 0x80 == 0x80
123
108
  v
124
109
  end
125
110
 
@@ -128,7 +113,7 @@ module RASN1
128
113
  return if @enum.nil?
129
114
 
130
115
  @value = @enum.key(@value)
131
- raise EnumeratedError, "TAG #{@name}: value #{v} not in enumeration" if @value.nil?
116
+ raise EnumeratedError, "#{@name}: value #{v} not in enumeration" if @value.nil?
132
117
  end
133
118
 
134
119
  def explicit_type
@@ -5,8 +5,8 @@ module RASN1
5
5
  # ASN.1 Null
6
6
  # @author Sylvain Daubert
7
7
  class Null < Primitive
8
- # Null tag value
9
- TAG = 0x05
8
+ # Null id value
9
+ ID = 0x05
10
10
 
11
11
  # @return [String]
12
12
  def inspect(level=0)
@@ -22,7 +22,7 @@ module RASN1
22
22
  end
23
23
 
24
24
  def der_to_value(der, ber: false)
25
- raise ASN1Error, 'NULL TAG should not have content!' if der.length.positive?
25
+ raise ASN1Error, 'NULL should not have content!' if der.length.positive?
26
26
 
27
27
  @value = nil
28
28
  end
@@ -5,8 +5,8 @@ module RASN1
5
5
  # ASN.1 Numeric String
6
6
  # @author Sylvain Daubert
7
7
  class NumericString < OctetString
8
- # NumericString tag value
9
- TAG = 18
8
+ # NumericString id value
9
+ ID = 18
10
10
 
11
11
  # Get ASN.1 type
12
12
  # @return [String]
@@ -21,15 +21,13 @@ module RASN1
21
21
  @value.to_s.force_encoding('BINARY')
22
22
  end
23
23
 
24
- def der_to_value(der, ber:false)
24
+ def der_to_value(der, ber: false)
25
25
  super
26
26
  check_characters
27
27
  end
28
28
 
29
29
  def check_characters
30
- if @value.to_s =~ /([^0-9 ])/
31
- raise ASN1Error, "NUMERIC STRING #{@name}: invalid character: '#{$1}'"
32
- end
30
+ raise ASN1Error, "NUMERIC STRING #{@name}: invalid character: '#{$1}'" if @value.to_s =~ /([^0-9 ])/
33
31
  end
34
32
  end
35
33
  end
@@ -2,77 +2,46 @@
2
2
 
3
3
  module RASN1
4
4
  module Types
5
-
6
5
  # ASN.1 Object ID
7
6
  # @author Sylvain Daubert
8
7
  class ObjectId < Primitive
9
- # ObjectId tag value
10
- TAG = 6
8
+ # ObjectId id value
9
+ ID = 6
11
10
 
12
11
  private
13
12
 
14
13
  def value_to_der
15
14
  ids = @value.split('.').map!(&:to_i)
16
15
 
17
- if ids[0] > 2
18
- raise ASN1Error, 'OBJECT ID #@name: first subidentifier should be less than 3'
19
- end
20
- if (ids[0] < 2) && (ids[1] > 39)
21
- raise ASN1Error, 'OBJECT ID #@name: second subidentifier should be less than 40'
22
- end
16
+ raise ASN1Error, "OBJECT ID #{@name}: first subidentifier should be less than 3" if ids[0] > 2
17
+ raise ASN1Error, "OBJECT ID #{@name}: second subidentifier should be less than 40" if (ids[0] < 2) && (ids[1] > 39)
23
18
 
24
19
  ids[0, 2] = ids[0] * 40 + ids[1]
25
20
  ids.map! do |v|
26
21
  next v if v < 128
27
22
 
28
- ary = []
29
- while v.positive?
30
- ary.unshift((v & 0x7f) | 0x80)
31
- v >>= 7
32
- end
33
- ary[-1] &= 0x7f
34
- ary
23
+ unsigned_to_chained_octets(v)
35
24
  end
36
25
  ids.flatten.pack('C*')
37
26
  end
38
27
 
39
28
  def der_to_value(der, ber: false)
40
29
  bytes = der.unpack('C*')
41
- nr_bytes_to_remove = 1
42
- ids = if bytes[0] < 80
43
- [bytes[0] / 40, bytes[0] % 40]
44
- elsif bytes[0] < 128
45
- [2, bytes[0] - 80]
46
- else
47
- second_id = bytes[0] & 0x7f
48
- bytes[1..-1].each do |byte|
49
- nr_bytes_to_remove += 1
50
- second_id <<= 7
51
- if byte < 128
52
- second_id |= byte
53
- break
54
- else
55
- second_id |= byte & 0x7f
56
- end
57
- end
58
- [2, second_id - 80]
59
- end
60
30
 
61
- id = 0
62
- bytes.shift(nr_bytes_to_remove)
31
+ ids = []
32
+ current_id = 0
63
33
  bytes.each do |byte|
64
- if byte < 128
65
- if id.zero?
66
- ids << byte
67
- else
68
- ids << ((id << 7) | byte)
69
- id = 0
70
- end
71
- else
72
- id = (id << 7) | (byte & 0x7f)
34
+ current_id = (current_id << 7) | (byte & 0x7f)
35
+ if (byte & 0x80).zero?
36
+ ids << current_id
37
+ current_id = 0
73
38
  end
74
39
  end
75
40
 
41
+ first_id = [2, ids.first / 40].min
42
+ second_id = ids.first - first_id * 40
43
+ ids[0..0] = [first_id, second_id]
44
+
76
45
  @value = ids.join('.')
77
46
  end
78
47
  end
@@ -12,8 +12,8 @@ module RASN1
12
12
  # os.to_der # => DER string with INTEGER in OCTET STRING
13
13
  # @author Sylvain Daubert
14
14
  class OctetString < Primitive
15
- # OctetString tag value
16
- TAG = 0x04
15
+ # OctetString id value
16
+ ID = 4
17
17
 
18
18
  def inspect(level=0)
19
19
  str = common_inspect(level)
@@ -5,8 +5,8 @@ module RASN1
5
5
  # ASN.1 Printable String
6
6
  # @author Sylvain Daubert
7
7
  class PrintableString < OctetString
8
- # PrintableString tag value
9
- TAG = 19
8
+ # PrintableString id value
9
+ ID = 19
10
10
 
11
11
  # Get ASN.1 type
12
12
  # @return [String]
@@ -21,15 +21,14 @@ module RASN1
21
21
  @value.to_s.force_encoding('BINARY')
22
22
  end
23
23
 
24
- def der_to_value(der, ber:false)
24
+ def der_to_value(der, ber: false)
25
25
  super
26
26
  check_characters
27
27
  end
28
28
 
29
29
  def check_characters
30
- if @value.to_s =~ /([^a-zA-Z0-9 '=\(\)\+,\-\.\/:\?])/
31
- raise ASN1Error, "PRINTABLE STRING #{@name}: invalid character: '#{$1}'"
32
- end
30
+ m = @value.to_s.match(%r{([^a-zA-Z0-9 '=()+,\-./:?])})
31
+ raise ASN1Error, "PRINTABLE STRING #{@name}: invalid character: '#{m[1]}'" if m
33
32
  end
34
33
  end
35
34
  end
@@ -26,8 +26,8 @@ module RASN1
26
26
  # seq.value # => String
27
27
  # @author Sylvain Daubert
28
28
  class Sequence < Constructed
29
- # Sequence tag value
30
- TAG = 0x10
29
+ # Sequence id value
30
+ ID = 0x10
31
31
 
32
32
  # @see Base#initialize
33
33
  def initialize(value_or_options={}, options={})