rasn1 0.6.8 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RASN1
2
4
  module Types
3
-
4
5
  # @abstract This is base class for all ASN.1 types.
5
6
  #
6
7
  # Subclasses SHOULD define:
@@ -46,11 +47,25 @@ module RASN1
46
47
  class Base
47
48
  # Allowed ASN.1 tag classes
48
49
  CLASSES = {
49
- universal: 0x00,
50
- application: 0x40,
51
- context: 0x80,
52
- private: 0xc0
53
- }
50
+ universal: 0x00,
51
+ application: 0x40,
52
+ context: 0x80,
53
+ private: 0xc0
54
+ }.freeze
55
+
56
+ # @private Types that cannot be dupped (Ruby <= 2.3)
57
+ UNDUPPABLE_TYPES = [[NilClass, nil], [TrueClass, true], [FalseClass, false], [Integer, 0]].map do |klass, obj|
58
+ begin
59
+ obj.dup
60
+ nil
61
+ rescue => TypeError
62
+ klass
63
+ end
64
+ end.compact.freeze
65
+
66
+ # Binary mask to get class
67
+ # @private
68
+ CLASS_MASK = 0xc0
54
69
 
55
70
  # Maximum ASN.1 tag number
56
71
  MAX_TAG = 0x1e
@@ -71,6 +86,7 @@ module RASN1
71
86
  # @return [String]
72
87
  def self.type
73
88
  return @type if defined? @type
89
+
74
90
  @type = self.to_s.gsub(/.*::/, '').gsub(/([a-z0-9])([A-Z])/, '\1 \2').upcase
75
91
  end
76
92
 
@@ -91,7 +107,6 @@ module RASN1
91
107
  obj
92
108
  end
93
109
 
94
-
95
110
  # @overload initialize(options={})
96
111
  # @param [Hash] options
97
112
  # @option options [Symbol] :class ASN.1 tag class. Default value is +:universal+.
@@ -128,20 +143,10 @@ module RASN1
128
143
  end
129
144
  end
130
145
 
131
- # Used by +#dup+ and +#clone+. Deep copy @value.
132
- def initialize_copy(other)
133
- @value = case
134
- when NilClass, TrueClass, FalseClass, Integer
135
- @value
136
- else
137
- @value.dup
138
- end
139
- @default = case
140
- when NilClass, TrueClass, FalseClass, Integer
141
- @default
142
- else
143
- @default.dup
144
- end
146
+ # Used by +#dup+ and +#clone+. Deep copy @value and @default.
147
+ def initialize_copy(_other)
148
+ @value = @value.dup unless UNDUPPABLE_TYPES.include?(@value.class)
149
+ @default = @default.dup unless UNDUPPABLE_TYPES.include?(@default.class)
145
150
  end
146
151
 
147
152
  # Get value or default value
@@ -192,7 +197,7 @@ module RASN1
192
197
 
193
198
  # @return [::Boolean] +true+ if this is a constructed type
194
199
  def constructed?
195
- !!((self.class < Constructed) || @constructed)
200
+ (self.class < Constructed) || !!@constructed
196
201
  end
197
202
 
198
203
  # Get ASN.1 type
@@ -206,9 +211,9 @@ module RASN1
206
211
  def tag
207
212
  pc = if @constructed.nil?
208
213
  self.class::ASN1_PC
209
- elsif @constructed # true
214
+ elsif @constructed # true
210
215
  Constructed::ASN1_PC
211
- else # false
216
+ else # false
212
217
  0
213
218
  end
214
219
  tag_value | CLASSES[@asn1_class] | pc
@@ -247,11 +252,9 @@ module RASN1
247
252
  # @param [Integer] level
248
253
  # @return [String]
249
254
  def inspect(level=0)
250
- str = ''
251
- str << ' ' * level if level > 0
252
- str << "#{@name} " unless @name.nil?
253
- str << "#{type}: #{value.inspect}"
254
- str << " OPTIONAL" if optional?
255
+ str = common_inspect(level)
256
+ str << " #{value.inspect}"
257
+ str << ' OPTIONAL' if optional?
255
258
  str << " DEFAULT #{@default}" unless @default.nil?
256
259
  str
257
260
  end
@@ -265,6 +268,13 @@ module RASN1
265
268
 
266
269
  private
267
270
 
271
+ def common_inspect(level)
272
+ lvl = level >= 0 ? level : 0
273
+ str = ' ' * lvl
274
+ str << "#{@name} " unless @name.nil?
275
+ str << "#{type}:"
276
+ end
277
+
268
278
  def value_to_der
269
279
  case @value
270
280
  when Base
@@ -274,7 +284,7 @@ module RASN1
274
284
  end
275
285
  end
276
286
 
277
- def der_to_value(der, ber:false)
287
+ def der_to_value(der, ber: false)
278
288
  @value = der
279
289
  end
280
290
 
@@ -292,11 +302,9 @@ module RASN1
292
302
  when nil
293
303
  @asn1_class = :universal
294
304
  when Symbol
295
- if CLASSES.keys.include? asn1_class
296
- @asn1_class = asn1_class
297
- else
298
- raise ClassError
299
- end
305
+ raise ClassError unless CLASSES.keys.include? asn1_class
306
+
307
+ @asn1_class = asn1_class
300
308
  else
301
309
  raise ClassError
302
310
  end
@@ -330,8 +338,8 @@ module RASN1
330
338
  end
331
339
 
332
340
  def build_tag?
333
- !(!@default.nil? and (@value.nil? or @value == @default)) and
334
- !(optional? and @value.nil?)
341
+ !(!@default.nil? && (@value.nil? || (@value == @default))) &&
342
+ !(optional? && @value.nil?)
335
343
  end
336
344
 
337
345
  def build_tag
@@ -356,22 +364,19 @@ module RASN1
356
364
  end
357
365
 
358
366
  def encode_tag
359
- if tag_value <= MAX_TAG
360
- [tag].pack('C')
361
- else
362
- raise ASN1Error, 'multi-byte tag value are not supported'
363
- end
367
+ raise ASN1Error, 'multi-byte tag value are not supported' unless tag_value <= MAX_TAG
368
+
369
+ [tag].pack('C')
364
370
  end
365
371
 
366
372
  def encode_size(size)
367
373
  if size >= INDEFINITE_LENGTH
368
374
  bytes = []
369
375
  while size > 255
370
- bytes << (size & 0xff)
376
+ bytes.unshift(size & 0xff)
371
377
  size >>= 8
372
378
  end
373
- bytes << size
374
- bytes.reverse!
379
+ bytes.unshift(size)
375
380
  bytes.unshift(INDEFINITE_LENGTH | bytes.size)
376
381
  bytes.pack('C*')
377
382
  else
@@ -402,27 +407,25 @@ module RASN1
402
407
  if length == INDEFINITE_LENGTH
403
408
  if primitive?
404
409
  raise ASN1Error, "malformed #{type} TAG: indefinite length " \
405
- "forbidden for primitive types"
410
+ 'forbidden for primitive types'
411
+ elsif ber
412
+ raise NotImplementedError, 'TAG: indefinite length not ' \
413
+ 'supported yet'
406
414
  else
407
- if ber
408
- raise NotImplementedError, "TAG: indefinite length not " \
409
- "supported yet"
410
- else
411
- raise ASN1Error, "TAG: indefinite length forbidden in DER " \
412
- "encoding"
413
- end
415
+ raise ASN1Error, 'TAG: indefinite length forbidden in DER ' \
416
+ 'encoding'
414
417
  end
415
418
  elsif length < INDEFINITE_LENGTH
416
419
  data = der[2, length]
417
420
  else
418
421
  length_length = length & 0x7f
419
- length = der[2, length_length].unpack('C*').
420
- reduce(0) { |len, b| (len << 8) | b }
422
+ length = der[2, length_length].unpack('C*')
423
+ .reduce(0) { |len, b| (len << 8) | b }
421
424
  data = der[2 + length_length, length]
422
425
  end
423
426
 
424
427
  total_length = 2 + length
425
- total_length += length_length if length_length > 0
428
+ total_length += length_length if length_length.positive?
426
429
 
427
430
  [total_length, data]
428
431
  end
@@ -432,14 +435,18 @@ module RASN1
432
435
  end
433
436
 
434
437
  def raise_tag_error(tag)
435
- msg = name.nil? ? '' : "#{name}: "
438
+ msg = name.nil? ? +'' : +"#{name}: "
436
439
  msg << "Expected #{self2name} but get #{tag2name(tag)}"
437
440
  raise ASN1Error, msg
438
441
  end
439
442
 
443
+ def class_from_numeric_tag(tag)
444
+ CLASSES.key(tag & CLASS_MASK)
445
+ end
446
+
440
447
  def self2name
441
- name = CLASSES.key(tag & 0xc0).to_s.upcase
442
- name << " #{tag & Constructed::ASN1_PC > 0 ? 'CONSTRUCTED' : 'PRIMITIVE'}"
448
+ name = class_from_numeric_tag(tag).to_s.upcase
449
+ name << " #{(tag & Constructed::ASN1_PC).positive? ? 'CONSTRUCTED' : 'PRIMITIVE'}"
443
450
  if implicit? || explicit?
444
451
  name << ' 0x%02X (0x%02X)' % [tag & 0x1f, tag]
445
452
  else
@@ -448,15 +455,15 @@ module RASN1
448
455
  end
449
456
 
450
457
  def tag2name(tag)
451
- return 'no tag' if tag.nil? or tag.empty?
458
+ return 'no tag' if tag.nil? || tag.empty?
452
459
 
453
460
  itag = tag.unpack('C').first
454
- name = CLASSES.key(itag & 0xc0).to_s.upcase
455
- name << " #{itag & Constructed::ASN1_PC > 0 ? 'CONSTRUCTED' : 'PRIMITIVE'}"
456
- type = Types.constants.map { |c| Types.const_get(c) }.
457
- select { |klass| klass < Primitive || klass < Constructed }.
458
- find { |klass| klass::TAG == itag & 0x1f }
459
- name << " #{type.nil? ? "0x%02X (0x%02X)" % [itag & 0x1f, itag] : type.encode_type }"
461
+ name = class_from_numeric_tag(itag).to_s.upcase
462
+ name << " #{(itag & Constructed::ASN1_PC).positive? ? 'CONSTRUCTED' : 'PRIMITIVE'}"
463
+ type = Types.constants.map { |c| Types.const_get(c) }
464
+ .select { |klass| klass < Primitive || klass < Constructed }
465
+ .find { |klass| klass::TAG == itag & 0x1f }
466
+ name << " #{type.nil? ? '0x%02X (0x%02X)' % [itag & 0x1f, itag] : type.encode_type}"
460
467
  end
461
468
  end
462
469
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RASN1
2
4
  module Types
3
-
4
5
  # ASN.1 Bit String
5
6
  # @author Sylvain Daubert
6
7
  class BitString < Primitive
8
+ # BitString tag value
7
9
  TAG = 0x03
8
10
 
9
11
  # @param [Integer] bit_length
@@ -25,7 +27,7 @@ module RASN1
25
27
  opts = value_or_options.is_a?(Hash) ? value_or_options : options
26
28
  if @default
27
29
  if opts[:bit_length].nil?
28
- raise ASN1Error, "TAG #@name: default bit length is not defined"
30
+ raise ASN1Error, "TAG #{@name}: default bit length is not defined"
29
31
  end
30
32
  @default_bit_length = opts[:bit_length]
31
33
  end
@@ -44,37 +46,33 @@ module RASN1
44
46
  # @param [Integer] level
45
47
  # @return [String]
46
48
  def inspect(level=0)
47
- str = ''
48
- str << ' ' * level if level > 0
49
- str << "#{name} " unless @name.nil?
50
- str << "#{type}: #{value.inspect} (bit length: #{bit_length})"
49
+ str = common_inspect(level)
50
+ str << " #{value.inspect} (bit length: #{bit_length})"
51
51
  end
52
52
 
53
53
  private
54
54
 
55
55
  def build_tag?
56
- !(!@default.nil? and (@value.nil? or @value == @default and
57
- @bit_length == @default_bit_length)) and
58
- !(optional? and @value.nil?)
56
+ !(!@default.nil? && (@value.nil? || (@value == @default) &&
57
+ (@bit_length == @default_bit_length))) &&
58
+ !(optional? && @value.nil?)
59
59
  end
60
60
 
61
61
  def value_to_der
62
- raise ASN1Error, "TAG #@name: bit length is not set" if bit_length.nil?
62
+ raise ASN1Error, "TAG #{@name}: bit length is not set" if bit_length.nil?
63
63
 
64
- while @value.length * 8 < @bit_length
65
- @value << "\x00"
66
- end
64
+ @value << "\x00" while @value.length * 8 < @bit_length
67
65
  @value.force_encoding('BINARY')
68
66
 
69
67
  if @value.length * 8 > @bit_length
70
- max_len = @bit_length / 8 + (@bit_length % 8 > 0 ? 1 : 0)
68
+ max_len = @bit_length / 8 + ((@bit_length % 8).positive? ? 1 : 0)
71
69
  @value = @value[0, max_len]
72
70
  end
73
71
 
74
72
  unused = @value.length * 8 - @bit_length
75
73
  der = [unused, @value].pack('CA*')
76
74
 
77
- if unused > 0
75
+ if unused.positive?
78
76
  last_byte = @value[-1].unpack('C').first
79
77
  last_byte &= (0xff >> unused) << unused
80
78
  der[-1] = [last_byte].pack('C')
@@ -83,7 +81,7 @@ module RASN1
83
81
  der
84
82
  end
85
83
 
86
- def der_to_value(der, ber:false)
84
+ def der_to_value(der, ber: false)
87
85
  unused, @value = der.unpack('CA*')
88
86
  @bit_length = @value.length * 8 - unused
89
87
  end
@@ -1,34 +1,37 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RASN1
2
4
  module Types
3
-
4
5
  # ASN.1 Boolean
5
6
  # @author Sylvain Daubert
6
7
  class Boolean < Primitive
8
+ # Boolean tag value
7
9
  TAG = 0x01
8
10
 
11
+ # @private
12
+ DER_TRUE = 0xff
13
+ # @private
14
+ DER_FALSE = 0
15
+
9
16
  private
10
17
 
11
18
  def value_to_der
12
- [@value ? 0xff : 0x00].pack('C')
19
+ [@value ? DER_TRUE : DER_FALSE].pack('C')
13
20
  end
14
21
 
15
22
  def der_to_value(der, ber: false)
16
- unless der.size == 1
17
- raise ASN1Error, "tag #@name: BOOLEAN should have a length of 1"
18
- end
23
+ raise ASN1Error, "tag #{@name}: BOOLEAN should have a length of 1" unless der.size == 1
19
24
 
20
25
  bool = der.unpack('C').first
21
26
  case bool
22
- when 0
27
+ when DER_FALSE
23
28
  @value = false
24
- when 0xff
29
+ when DER_TRUE
25
30
  @value = true
26
31
  else
27
- if ber
28
- @value = true
29
- else
30
- raise ASN1Error, "tag #@name: bad value 0x%02x for BOOLEAN" % bool
31
- end
32
+ raise ASN1Error, "tag #{@name}: bad value 0x%02x for BOOLEAN" % bool unless ber
33
+
34
+ @value = true
32
35
  end
33
36
  end
34
37
  end
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RASN1
2
4
  module Types
3
-
4
5
  # A ASN.1 CHOICE is a choice between different types.
5
6
  #
6
7
  # == Create a CHOICE
@@ -31,7 +32,6 @@ module RASN1
31
32
  # choice.chosen_value # => "abc"
32
33
  # @author Sylvain Daubert
33
34
  class Choice < Base
34
-
35
35
  # Chosen type
36
36
  # @return [Integer] index of type in choice value
37
37
  attr_accessor :chosen
@@ -87,19 +87,16 @@ module RASN1
87
87
  next
88
88
  end
89
89
  end
90
- raise ASN1Error, "CHOICE #@name: no type matching #{der.inspect}" unless parsed
90
+ raise ASN1Error, "CHOICE #{@name}: no type matching #{der.inspect}" unless parsed
91
91
  end
92
92
 
93
93
  def inspect(level=0)
94
- str = ''
95
- str << ' ' * level if level > 0
96
- str << "#{name} " if name
97
- str << "#{type}:"
98
- if !defined? @chosen
99
- str << ' not chosen!'
100
- else
101
- str << "\n#{@value[@chosen].inspect(level+1)}"
102
- end
94
+ str = common_inspect(level)
95
+ str << if !defined? @chosen
96
+ ' not chosen!'
97
+ else
98
+ "\n#{@value[@chosen].inspect(level + 1)}"
99
+ end
103
100
  end
104
101
 
105
102
  private
@@ -110,5 +107,3 @@ module RASN1
110
107
  end
111
108
  end
112
109
  end
113
-
114
-
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RASN1
2
4
  module Types
3
-
4
5
  # @abstract This class SHOULD be used as base class for all ASN.1 primitive
5
6
  # types.
6
7
  # Base class for all ASN.1 constructed types
@@ -12,19 +13,17 @@ module RASN1
12
13
  def inspect(level=0)
13
14
  case @value
14
15
  when Array
15
- str = ''
16
- str << ' ' * level if level > 0
17
- str << "#{@name} " unless @name.nil?
18
- level = level.abs
19
- str << "#{type}:\n"
20
- level += 1
16
+ str = common_inspect(level)
17
+ str << "\n"
18
+ level = level.abs + 1
21
19
  @value.each do |item|
22
20
  case item
23
21
  when Base, Model
24
- next if item.optional? and item.value.nil?
22
+ next if item.optional? && item.value.nil?
23
+
25
24
  str << "#{item.inspect(level)}\n"
26
25
  else
27
- str << ' ' * level + item.inspect + "\n"
26
+ str << ' ' * level + item.inspect + "\n"
28
27
  end
29
28
  end
30
29
  str