rasn1 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rasn1.rb +1 -1
- data/lib/rasn1/model.rb +25 -28
- data/lib/rasn1/types.rb +41 -15
- data/lib/rasn1/types/any.rb +5 -1
- data/lib/rasn1/types/base.rb +102 -85
- data/lib/rasn1/types/bit_string.rb +9 -11
- data/lib/rasn1/types/boolean.rb +3 -3
- data/lib/rasn1/types/choice.rb +1 -1
- data/lib/rasn1/types/constructed.rb +2 -1
- data/lib/rasn1/types/enumerated.rb +2 -2
- data/lib/rasn1/types/generalized_time.rb +2 -2
- data/lib/rasn1/types/ia5string.rb +2 -2
- data/lib/rasn1/types/integer.rb +26 -41
- data/lib/rasn1/types/null.rb +3 -3
- data/lib/rasn1/types/numeric_string.rb +4 -6
- data/lib/rasn1/types/object_id.rb +15 -46
- data/lib/rasn1/types/octet_string.rb +2 -2
- data/lib/rasn1/types/printable_string.rb +5 -6
- data/lib/rasn1/types/sequence.rb +2 -2
- data/lib/rasn1/types/sequence_of.rb +3 -3
- data/lib/rasn1/types/set.rb +2 -2
- data/lib/rasn1/types/set_of.rb +2 -2
- data/lib/rasn1/types/utc_time.rb +2 -2
- data/lib/rasn1/types/utf8_string.rb +2 -2
- data/lib/rasn1/types/visible_string.rb +2 -2
- data/lib/rasn1/version.rb +1 -1
- metadata +26 -56
- data/.gitignore +0 -11
- data/.rubocop.yml +0 -32
- data/.travis.yml +0 -11
- data/Changelog.md +0 -15
- data/Gemfile +0 -4
- data/Rakefile +0 -12
- data/rasn1.gemspec +0 -32
@@ -5,8 +5,8 @@ module RASN1
|
|
5
5
|
# ASN.1 Bit String
|
6
6
|
# @author Sylvain Daubert
|
7
7
|
class BitString < Primitive
|
8
|
-
# BitString
|
9
|
-
|
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
|
30
|
-
|
31
|
-
|
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 =
|
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
|
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, "
|
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].
|
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
|
data/lib/rasn1/types/boolean.rb
CHANGED
@@ -5,8 +5,8 @@ module RASN1
|
|
5
5
|
# ASN.1 Boolean
|
6
6
|
# @author Sylvain Daubert
|
7
7
|
class Boolean < Primitive
|
8
|
-
# Boolean
|
9
|
-
|
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.
|
25
|
+
bool = der.unpack1('C')
|
26
26
|
case bool
|
27
27
|
when DER_FALSE
|
28
28
|
@value = false
|
data/lib/rasn1/types/choice.rb
CHANGED
data/lib/rasn1/types/integer.rb
CHANGED
@@ -8,8 +8,8 @@ module RASN1
|
|
8
8
|
# @return [Hash,nil]
|
9
9
|
attr_reader :enum
|
10
10
|
|
11
|
-
# Integer
|
12
|
-
|
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
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
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, "
|
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=(
|
54
|
-
case
|
55
|
-
when String,Symbol
|
56
|
-
raise EnumeratedError, "
|
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
|
-
|
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 =
|
65
|
-
elsif @enum.value?
|
66
|
-
@value = @enum.key(
|
57
|
+
@value = val
|
58
|
+
elsif @enum.value? val
|
59
|
+
@value = @enum.key(val)
|
67
60
|
else
|
68
|
-
raise EnumeratedError, "
|
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, "
|
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 =
|
94
|
-
|
95
|
-
|
96
|
-
|
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, "
|
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, "
|
116
|
+
raise EnumeratedError, "#{@name}: value #{v} not in enumeration" if @value.nil?
|
132
117
|
end
|
133
118
|
|
134
119
|
def explicit_type
|
data/lib/rasn1/types/null.rb
CHANGED
@@ -5,8 +5,8 @@ module RASN1
|
|
5
5
|
# ASN.1 Null
|
6
6
|
# @author Sylvain Daubert
|
7
7
|
class Null < Primitive
|
8
|
-
# Null
|
9
|
-
|
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
|
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
|
9
|
-
|
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
|
10
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
62
|
-
|
31
|
+
ids = []
|
32
|
+
current_id = 0
|
63
33
|
bytes.each do |byte|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
16
|
-
|
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
|
9
|
-
|
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
|
-
|
31
|
-
|
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
|
data/lib/rasn1/types/sequence.rb
CHANGED