rasn1 0.6.6 → 0.8.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.
- checksums.yaml +4 -4
- data/README.md +11 -2
- data/lib/rasn1.rb +7 -6
- data/lib/rasn1/model.rb +108 -59
- data/lib/rasn1/types.rb +49 -20
- data/lib/rasn1/types/any.rb +26 -16
- data/lib/rasn1/types/base.rb +146 -115
- data/lib/rasn1/types/bit_string.rb +20 -24
- data/lib/rasn1/types/boolean.rb +17 -14
- data/lib/rasn1/types/choice.rb +11 -16
- data/lib/rasn1/types/constructed.rb +9 -9
- data/lib/rasn1/types/enumerated.rb +4 -2
- data/lib/rasn1/types/generalized_time.rb +24 -26
- data/lib/rasn1/types/ia5string.rb +7 -5
- data/lib/rasn1/types/integer.rb +32 -45
- data/lib/rasn1/types/null.rb +8 -8
- data/lib/rasn1/types/numeric_string.rb +7 -7
- data/lib/rasn1/types/object_id.rb +18 -48
- data/lib/rasn1/types/octet_string.rb +6 -6
- data/lib/rasn1/types/primitive.rb +2 -1
- data/lib/rasn1/types/printable_string.rb +8 -7
- data/lib/rasn1/types/sequence.rb +21 -7
- data/lib/rasn1/types/sequence_of.rb +15 -13
- data/lib/rasn1/types/set.rb +4 -2
- data/lib/rasn1/types/set_of.rb +4 -3
- data/lib/rasn1/types/utc_time.rb +6 -4
- data/lib/rasn1/types/utf8_string.rb +6 -4
- data/lib/rasn1/types/visible_string.rb +4 -3
- data/lib/rasn1/version.rb +3 -1
- metadata +27 -50
- data/.gitignore +0 -11
- data/.rubocop.yml +0 -29
- data/.travis.yml +0 -9
- data/Gemfile +0 -4
- data/Rakefile +0 -12
- data/rasn1.gemspec +0 -32
| @@ -1,10 +1,12 @@ | |
| 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
         | 
| 7 | 
            -
                   | 
| 8 | 
            +
                  # BitString id value
         | 
| 9 | 
            +
                  ID = 3
         | 
| 8 10 |  | 
| 9 11 | 
             
                  # @param [Integer] bit_length
         | 
| 10 12 | 
             
                  # @return [Integer]
         | 
| @@ -22,14 +24,12 @@ module RASN1 | |
| 22 24 | 
             
                  # @see Base#initialize common options to all ASN.1 types
         | 
| 23 25 | 
             
                  def initialize(value_or_options={}, options={})
         | 
| 24 26 | 
             
                    super
         | 
| 25 | 
            -
                    opts = value_or_options.is_a?(Hash) ? value_or_options : options
         | 
| 26 27 | 
             
                    if @default
         | 
| 27 | 
            -
                      if  | 
| 28 | 
            -
             | 
| 29 | 
            -
                       | 
| 30 | 
            -
                      @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]
         | 
| 31 31 | 
             
                    end
         | 
| 32 | 
            -
                    @bit_length =  | 
| 32 | 
            +
                    @bit_length = @options[:bit_length]
         | 
| 33 33 | 
             
                  end
         | 
| 34 34 |  | 
| 35 35 | 
             
                  # Get bit length
         | 
| @@ -44,38 +44,34 @@ module RASN1 | |
| 44 44 | 
             
                  # @param [Integer] level
         | 
| 45 45 | 
             
                  # @return [String]
         | 
| 46 46 | 
             
                  def inspect(level=0)
         | 
| 47 | 
            -
                    str =  | 
| 48 | 
            -
                    str <<  | 
| 49 | 
            -
                    str << "#{name} " unless @name.nil?
         | 
| 50 | 
            -
                    str << "#{type}: #{value.inspect} (bit length: #{bit_length})"
         | 
| 47 | 
            +
                    str = common_inspect(level)
         | 
| 48 | 
            +
                    str << " #{value.inspect} (bit length: #{bit_length})"
         | 
| 51 49 | 
             
                  end
         | 
| 52 50 |  | 
| 53 51 | 
             
                  private
         | 
| 54 52 |  | 
| 55 | 
            -
                  def  | 
| 56 | 
            -
                    !(!@default.nil?  | 
| 57 | 
            -
                                          @bit_length == @default_bit_length))  | 
| 58 | 
            -
                      !(optional?  | 
| 53 | 
            +
                  def can_build?
         | 
| 54 | 
            +
                    !(!@default.nil? && (@value.nil? || (@value == @default) &&
         | 
| 55 | 
            +
                                          (@bit_length == @default_bit_length))) &&
         | 
| 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 | 
            -
                    while @value.length * 8 < @bit_length
         | 
| 65 | 
            -
                      @value << "\x00"
         | 
| 66 | 
            -
                    end
         | 
| 62 | 
            +
                    @value << "\x00" while @value.length * 8 < @bit_length
         | 
| 67 63 | 
             
                    @value.force_encoding('BINARY')
         | 
| 68 64 |  | 
| 69 65 | 
             
                    if @value.length * 8 > @bit_length
         | 
| 70 | 
            -
                      max_len = @bit_length / 8 + (@bit_length % 8  | 
| 66 | 
            +
                      max_len = @bit_length / 8 + ((@bit_length % 8).positive? ? 1 : 0)
         | 
| 71 67 | 
             
                      @value = @value[0, max_len]
         | 
| 72 68 | 
             
                    end
         | 
| 73 69 |  | 
| 74 70 | 
             
                    unused = @value.length * 8 - @bit_length
         | 
| 75 71 | 
             
                    der = [unused, @value].pack('CA*')
         | 
| 76 72 |  | 
| 77 | 
            -
                    if unused | 
| 78 | 
            -
                      last_byte = @value[-1]. | 
| 73 | 
            +
                    if unused.positive?
         | 
| 74 | 
            +
                      last_byte = @value[-1].unpack1('C')
         | 
| 79 75 | 
             
                      last_byte &= (0xff >> unused) << unused
         | 
| 80 76 | 
             
                      der[-1] = [last_byte].pack('C')
         | 
| 81 77 | 
             
                    end
         | 
| @@ -83,7 +79,7 @@ module RASN1 | |
| 83 79 | 
             
                    der
         | 
| 84 80 | 
             
                  end
         | 
| 85 81 |  | 
| 86 | 
            -
                  def der_to_value(der, ber:false)
         | 
| 82 | 
            +
                  def der_to_value(der, ber: false)
         | 
| 87 83 | 
             
                    unused, @value = der.unpack('CA*')
         | 
| 88 84 | 
             
                    @bit_length = @value.length * 8 - unused
         | 
| 89 85 | 
             
                  end
         | 
    
        data/lib/rasn1/types/boolean.rb
    CHANGED
    
    | @@ -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
         | 
| 7 | 
            -
                   | 
| 8 | 
            +
                  # Boolean id value
         | 
| 9 | 
            +
                  ID = 0x01
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  # @private
         | 
| 12 | 
            +
                  DER_TRUE = 0xff
         | 
| 13 | 
            +
                  # @private
         | 
| 14 | 
            +
                  DER_FALSE = 0
         | 
| 8 15 |  | 
| 9 16 | 
             
                  private
         | 
| 10 17 |  | 
| 11 18 | 
             
                  def value_to_der
         | 
| 12 | 
            -
                    [@value ?  | 
| 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 | 
            -
                    bool = der. | 
| 25 | 
            +
                    bool = der.unpack1('C')
         | 
| 21 26 | 
             
                    case bool
         | 
| 22 | 
            -
                    when  | 
| 27 | 
            +
                    when DER_FALSE
         | 
| 23 28 | 
             
                      @value = false
         | 
| 24 | 
            -
                    when  | 
| 29 | 
            +
                    when DER_TRUE
         | 
| 25 30 | 
             
                      @value = true
         | 
| 26 31 | 
             
                    else
         | 
| 27 | 
            -
                       | 
| 28 | 
            -
             | 
| 29 | 
            -
                       | 
| 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
         | 
    
        data/lib/rasn1/types/choice.rb
    CHANGED
    
    | @@ -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
         | 
| @@ -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
         | 
| @@ -87,28 +87,23 @@ module RASN1 | |
| 87 87 | 
             
                        next
         | 
| 88 88 | 
             
                      end
         | 
| 89 89 | 
             
                    end
         | 
| 90 | 
            -
                    raise ASN1Error, "CHOICE  | 
| 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 <<  | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 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
         | 
| 106 103 |  | 
| 107 104 | 
             
                  def check_chosen
         | 
| 108 | 
            -
                    raise ChoiceError if @chosen.nil?
         | 
| 105 | 
            +
                    raise ChoiceError if !defined?(@chosen) || @chosen.nil?
         | 
| 109 106 | 
             
                  end
         | 
| 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,18 @@ module RASN1 | |
| 12 13 | 
             
                  def inspect(level=0)
         | 
| 13 14 | 
             
                    case @value
         | 
| 14 15 | 
             
                    when Array
         | 
| 15 | 
            -
                      str =  | 
| 16 | 
            -
                      str <<  | 
| 17 | 
            -
                       | 
| 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?  | 
| 22 | 
            +
                          next if item.optional? && item.value.nil?
         | 
| 23 | 
            +
             | 
| 25 24 | 
             
                          str << "#{item.inspect(level)}\n"
         | 
| 26 25 | 
             
                        else
         | 
| 27 | 
            -
                          str << | 
| 26 | 
            +
                          str << '  ' * level
         | 
| 27 | 
            +
                          str << "#{item.inspect}\n"
         | 
| 28 28 | 
             
                        end
         | 
| 29 29 | 
             
                      end
         | 
| 30 30 | 
             
                      str
         | 
| @@ -1,6 +1,7 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module RASN1
         | 
| 2 4 | 
             
              module Types
         | 
| 3 | 
            -
             | 
| 4 5 | 
             
                # ASN.1 Enumerated
         | 
| 5 6 | 
             
                #
         | 
| 6 7 | 
             
                # An enumerated type permits to assign names to integer values. It may be defined
         | 
| @@ -21,7 +22,8 @@ module RASN1 | |
| 21 22 | 
             
                  # @!attribute enum
         | 
| 22 23 | 
             
                  # @return [Hash]
         | 
| 23 24 |  | 
| 24 | 
            -
                   | 
| 25 | 
            +
                  # Enumerated id value
         | 
| 26 | 
            +
                  ID = 0x0a
         | 
| 25 27 |  | 
| 26 28 | 
             
                  # @overload initialize(options={})
         | 
| 27 29 | 
             
                  #   @option options [Hash] :enum enumeration hash. Keys are names, and values
         | 
| @@ -1,6 +1,7 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module RASN1
         | 
| 2 4 | 
             
              module Types
         | 
| 3 | 
            -
             | 
| 4 5 | 
             
                # ASN.1 GeneralizedTime
         | 
| 5 6 | 
             
                #
         | 
| 6 7 | 
             
                # +{#value} of a {GeneralizedTime} should be a ruby Time.
         | 
| @@ -20,7 +21,8 @@ module RASN1 | |
| 20 21 | 
             
                # second are supported.
         | 
| 21 22 | 
             
                # @author Sylvain Daubert
         | 
| 22 23 | 
             
                class GeneralizedTime < Primitive
         | 
| 23 | 
            -
                   | 
| 24 | 
            +
                  # GeneralizedTime id value
         | 
| 25 | 
            +
                  ID = 24
         | 
| 24 26 |  | 
| 25 27 | 
             
                  # Get ASN.1 type
         | 
| 26 28 | 
             
                  # @return [String]
         | 
| @@ -29,50 +31,48 @@ module RASN1 | |
| 29 31 | 
             
                  end
         | 
| 30 32 |  | 
| 31 33 | 
             
                  private
         | 
| 32 | 
            -
             | 
| 34 | 
            +
             | 
| 33 35 | 
             
                  def value_to_der
         | 
| 34 | 
            -
                    if @value.nsec | 
| 36 | 
            +
                    if @value.nsec.positive?
         | 
| 35 37 | 
             
                      der = @value.getutc.strftime('%Y%m%d%H%M%S.%9NZ')
         | 
| 36 38 | 
             
                      der.sub(/0+Z/, 'Z')
         | 
| 37 39 | 
             
                    else
         | 
| 38 40 | 
             
                      @value.getutc.strftime('%Y%m%d%H%M%SZ')
         | 
| 39 41 | 
             
                    end
         | 
| 40 42 | 
             
                  end
         | 
| 41 | 
            -
             | 
| 43 | 
            +
             | 
| 42 44 | 
             
                  def der_to_value(der, ber: false)
         | 
| 43 45 | 
             
                    date_hour, fraction = der.split('.')
         | 
| 44 46 | 
             
                    utc_offset_forced = false
         | 
| 45 47 | 
             
                    if fraction.nil?
         | 
| 46 | 
            -
                      if date_hour[-1] != 'Z'  | 
| 48 | 
            +
                      if (date_hour[-1] != 'Z') && (date_hour !~ /[+-]\d+$/)
         | 
| 47 49 | 
             
                        # If not UTC, have to add offset with UTC to force
         | 
| 48 50 | 
             
                        # DateTime#strptime to generate a local time. But this difference
         | 
| 49 51 | 
             
                        # may be errored because of DST.
         | 
| 50 52 | 
             
                        date_hour << Time.now.strftime('%z')
         | 
| 51 53 | 
             
                        utc_offset_forced = true
         | 
| 52 54 | 
             
                      end
         | 
| 55 | 
            +
                    elsif fraction[-1] == 'Z'
         | 
| 56 | 
            +
                      fraction = fraction[0...-1]
         | 
| 57 | 
            +
                      date_hour << 'Z'
         | 
| 53 58 | 
             
                    else
         | 
| 54 | 
            -
                       | 
| 55 | 
            -
             | 
| 56 | 
            -
                         | 
| 59 | 
            +
                      match = fraction.match(/(\d+)([+-]\d+)/)
         | 
| 60 | 
            +
                      if match
         | 
| 61 | 
            +
                        # fraction contains fraction and timezone info. Split them
         | 
| 62 | 
            +
                        fraction = match[1]
         | 
| 63 | 
            +
                        date_hour << match[2]
         | 
| 57 64 | 
             
                      else
         | 
| 58 | 
            -
                         | 
| 59 | 
            -
                         | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
                         | 
| 64 | 
            -
                          # fraction only contains fraction.
         | 
| 65 | 
            -
                          # Have to add offset with UTC to force DateTime#strptime to
         | 
| 66 | 
            -
                          # generate a local time. But this difference may be errored
         | 
| 67 | 
            -
                          # because of DST.
         | 
| 68 | 
            -
                          date_hour << Time.now.strftime('%z')
         | 
| 69 | 
            -
                          utc_offset_forced = true
         | 
| 70 | 
            -
                        end
         | 
| 65 | 
            +
                        # fraction only contains fraction.
         | 
| 66 | 
            +
                        # Have to add offset with UTC to force DateTime#strptime to
         | 
| 67 | 
            +
                        # generate a local time. But this difference may be errored
         | 
| 68 | 
            +
                        # because of DST.
         | 
| 69 | 
            +
                        date_hour << Time.now.strftime('%z')
         | 
| 70 | 
            +
                        utc_offset_forced = true
         | 
| 71 71 | 
             
                      end
         | 
| 72 72 | 
             
                    end
         | 
| 73 73 | 
             
                    format = case date_hour.size
         | 
| 74 74 | 
             
                             when 11
         | 
| 75 | 
            -
                               frac_base = 60*60
         | 
| 75 | 
            +
                               frac_base = 60 * 60
         | 
| 76 76 | 
             
                               '%Y%m%d%HZ'
         | 
| 77 77 | 
             
                             when 13
         | 
| 78 78 | 
             
                               frac_base = 60
         | 
| @@ -100,9 +100,7 @@ module RASN1 | |
| 100 100 | 
             
                    # Check DST. There may be a shift of one hour...
         | 
| 101 101 | 
             
                    if utc_offset_forced
         | 
| 102 102 | 
             
                      compare_time = Time.new(*@value.to_a[0..5].reverse)
         | 
| 103 | 
            -
                      if compare_time.utc_offset != @value.utc_offset
         | 
| 104 | 
            -
                        @value = compare_time
         | 
| 105 | 
            -
                      end
         | 
| 103 | 
            +
                      @value = compare_time if compare_time.utc_offset != @value.utc_offset
         | 
| 106 104 | 
             
                    end
         | 
| 107 105 | 
             
                    @value += ".#{fraction}".to_r * frac_base unless fraction.nil?
         | 
| 108 106 | 
             
                  end
         | 
| @@ -1,10 +1,12 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module RASN1
         | 
| 2 4 | 
             
              module Types
         | 
| 3 | 
            -
             | 
| 4 5 | 
             
                # ASN.1 IA5 String
         | 
| 5 6 | 
             
                # @author Sylvain Daubert
         | 
| 6 7 | 
             
                class IA5String < OctetString
         | 
| 7 | 
            -
                   | 
| 8 | 
            +
                  # IA5String id value
         | 
| 9 | 
            +
                  ID = 22
         | 
| 8 10 |  | 
| 9 11 | 
             
                  # Get ASN.1 type
         | 
| 10 12 | 
             
                  # @return [String]
         | 
| @@ -13,15 +15,15 @@ module RASN1 | |
| 13 15 | 
             
                  end
         | 
| 14 16 |  | 
| 15 17 | 
             
                  private
         | 
| 16 | 
            -
             | 
| 18 | 
            +
             | 
| 17 19 | 
             
                  def value_to_der
         | 
| 18 20 | 
             
                    @value.to_s.force_encoding('US-ASCII').force_encoding('BINARY')
         | 
| 19 21 | 
             
                  end
         | 
| 20 22 |  | 
| 21 | 
            -
                  def der_to_value(der, ber:false)
         | 
| 23 | 
            +
                  def der_to_value(der, ber: false)
         | 
| 22 24 | 
             
                    super
         | 
| 23 25 | 
             
                    @value.force_encoding('US-ASCII')
         | 
| 24 26 | 
             
                  end
         | 
| 25 | 
            -
             | 
| 27 | 
            +
                end
         | 
| 26 28 | 
             
              end
         | 
| 27 29 | 
             
            end
         | 
    
        data/lib/rasn1/types/integer.rb
    CHANGED
    
    | @@ -1,13 +1,15 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module RASN1
         | 
| 2 4 | 
             
              module Types
         | 
| 3 | 
            -
             | 
| 4 5 | 
             
                # ASN.1 Integer
         | 
| 5 6 | 
             
                # @author Sylvain Daubert
         | 
| 6 7 | 
             
                class Integer < Primitive
         | 
| 7 8 | 
             
                  # @return [Hash,nil]
         | 
| 8 9 | 
             
                  attr_reader :enum
         | 
| 9 10 |  | 
| 10 | 
            -
                   | 
| 11 | 
            +
                  # Integer id value
         | 
| 12 | 
            +
                  ID = 2
         | 
| 11 13 |  | 
| 12 14 | 
             
                  # @overload initialize(options={})
         | 
| 13 15 | 
             
                  #   @option options [Hash] :enum enumeration hash. Keys are names, and values
         | 
| @@ -21,8 +23,7 @@ module RASN1 | |
| 21 23 | 
             
                  # @see Base#initialize common options to all ASN.1 types
         | 
| 22 24 | 
             
                  def initialize(value_or_options={}, options={})
         | 
| 23 25 | 
             
                    super
         | 
| 24 | 
            -
                     | 
| 25 | 
            -
                    @enum = opts[:enum]
         | 
| 26 | 
            +
                    @enum = @options[:enum]
         | 
| 26 27 |  | 
| 27 28 | 
             
                    return if @enum.nil?
         | 
| 28 29 |  | 
| @@ -30,45 +31,39 @@ module RASN1 | |
| 30 31 | 
             
                    self.value = @value
         | 
| 31 32 |  | 
| 32 33 | 
             
                    case @default
         | 
| 33 | 
            -
                    when String,Symbol
         | 
| 34 | 
            -
                      unless @enum. | 
| 35 | 
            -
                        raise EnumeratedError, "TAG #@name: unknwon enumerated default value #@default"
         | 
| 36 | 
            -
                      end
         | 
| 34 | 
            +
                    when String, Symbol
         | 
| 35 | 
            +
                      raise EnumeratedError, "#{@name}: unknwon enumerated default value #@{default}" unless @enum.key? @default
         | 
| 37 36 | 
             
                    when ::Integer
         | 
| 38 | 
            -
                       | 
| 39 | 
            -
             | 
| 40 | 
            -
                       | 
| 41 | 
            -
                        raise EnumeratedError, "TAG #@name: default value #@default not in enumeration"
         | 
| 42 | 
            -
                      end
         | 
| 37 | 
            +
                      raise EnumeratedError, "#{@name}: default value #@{default} not in enumeration" unless @enum.value? @default
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                      @default = @enum.key(@default)
         | 
| 43 40 | 
             
                    when nil
         | 
| 44 41 | 
             
                    else
         | 
| 45 | 
            -
                      raise TypeError, " | 
| 42 | 
            +
                      raise TypeError, "#{@name}: #{@default.class} not handled as default value"
         | 
| 46 43 | 
             
                    end
         | 
| 47 44 | 
             
                  end
         | 
| 48 45 |  | 
| 49 46 | 
             
                  # @param [Integer,String,Symbol,nil] v
         | 
| 50 47 | 
             
                  # @return [String,Symbol,nil]
         | 
| 51 | 
            -
                  def value=( | 
| 52 | 
            -
                    case  | 
| 53 | 
            -
                    when String,Symbol
         | 
| 54 | 
            -
                      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
         | 
| 55 53 |  | 
| 56 | 
            -
                       | 
| 57 | 
            -
                        raise EnumeratedError, "TAG #@name: unknwon enumerated value #{v}"
         | 
| 58 | 
            -
                      end
         | 
| 59 | 
            -
                      @value = v
         | 
| 54 | 
            +
                      @value = val
         | 
| 60 55 | 
             
                    when ::Integer
         | 
| 61 56 | 
             
                      if @enum.nil?
         | 
| 62 | 
            -
                        @value =  | 
| 63 | 
            -
                      elsif @enum. | 
| 64 | 
            -
                        @value = @enum.key( | 
| 57 | 
            +
                        @value = val
         | 
| 58 | 
            +
                      elsif @enum.value? val
         | 
| 59 | 
            +
                        @value = @enum.key(val)
         | 
| 65 60 | 
             
                      else
         | 
| 66 | 
            -
                        raise EnumeratedError, " | 
| 61 | 
            +
                        raise EnumeratedError, "#{@name}: #{val} not in enumeration"
         | 
| 67 62 | 
             
                      end
         | 
| 68 63 | 
             
                    when nil
         | 
| 69 64 | 
             
                      @value = nil
         | 
| 70 65 | 
             
                    else
         | 
| 71 | 
            -
                      raise EnumeratedError, " | 
| 66 | 
            +
                      raise EnumeratedError, "#{@name}: not in enumeration"
         | 
| 72 67 | 
             
                    end
         | 
| 73 68 | 
             
                  end
         | 
| 74 69 |  | 
| @@ -86,18 +81,12 @@ module RASN1 | |
| 86 81 |  | 
| 87 82 | 
             
                  def int_value_to_der(value=nil)
         | 
| 88 83 | 
             
                    v = value || @value
         | 
| 89 | 
            -
                    size = v.bit_length / 8 + (v.bit_length % 8  | 
| 90 | 
            -
                    size = 1 if size | 
| 91 | 
            -
                    comp_value =  | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
                                   v
         | 
| 96 | 
            -
                                 else
         | 
| 97 | 
            -
                                   ~(v.abs) + 1
         | 
| 98 | 
            -
                                 end
         | 
| 99 | 
            -
                    ary = []
         | 
| 100 | 
            -
                    size.times { ary << (comp_value & 0xff); comp_value >>= 8 }
         | 
| 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)
         | 
| 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)
         | 
| 101 90 | 
             
                    ary.reverse.pack('C*')
         | 
| 102 91 | 
             
                  end
         | 
| 103 92 |  | 
| @@ -108,16 +97,14 @@ module RASN1 | |
| 108 97 | 
             
                    when ::Integer
         | 
| 109 98 | 
             
                      int_value_to_der
         | 
| 110 99 | 
             
                    else
         | 
| 111 | 
            -
                      raise TypeError, " | 
| 100 | 
            +
                      raise TypeError, "#{@name}: #{@value.class} not handled"
         | 
| 112 101 | 
             
                    end
         | 
| 113 102 | 
             
                  end
         | 
| 114 103 |  | 
| 115 104 | 
             
                  def der_to_int_value(der, ber: false)
         | 
| 116 105 | 
             
                    ary = der.unpack('C*')
         | 
| 117 106 | 
             
                    v = ary.reduce(0) { |len, b| (len << 8) | b }
         | 
| 118 | 
            -
                    if ary[0] & 0x80 == 0x80
         | 
| 119 | 
            -
                      v = -((~v & ((1 << v.bit_length) - 1)) + 1)
         | 
| 120 | 
            -
                    end
         | 
| 107 | 
            +
                    v = -((~v & ((1 << v.bit_length) - 1)) + 1) if ary[0] & 0x80 == 0x80
         | 
| 121 108 | 
             
                    v
         | 
| 122 109 | 
             
                  end
         | 
| 123 110 |  | 
| @@ -126,11 +113,11 @@ module RASN1 | |
| 126 113 | 
             
                    return if @enum.nil?
         | 
| 127 114 |  | 
| 128 115 | 
             
                    @value = @enum.key(@value)
         | 
| 129 | 
            -
                    raise EnumeratedError, " | 
| 116 | 
            +
                    raise EnumeratedError, "#{@name}: value #{v} not in enumeration" if @value.nil?
         | 
| 130 117 | 
             
                  end
         | 
| 131 118 |  | 
| 132 119 | 
             
                  def explicit_type
         | 
| 133 | 
            -
                     | 
| 120 | 
            +
                    self.class.new(name: @name, enum: @enum)
         | 
| 134 121 | 
             
                  end
         | 
| 135 122 | 
             
                end
         | 
| 136 123 | 
             
              end
         |