Module: RASN1::Types

Defined in:
lib/rasn1/types.rb,
lib/rasn1/tracer.rb,
lib/rasn1/types/any.rb,
lib/rasn1/types/set.rb,
lib/rasn1/types/base.rb,
lib/rasn1/types/null.rb,
lib/rasn1/types/choice.rb,
lib/rasn1/types/set_of.rb,
lib/rasn1/types/boolean.rb,
lib/rasn1/types/integer.rb,
lib/rasn1/types/sequence.rb,
lib/rasn1/types/utc_time.rb,
lib/rasn1/types/ia5string.rb,
lib/rasn1/types/object_id.rb,
lib/rasn1/types/primitive.rb,
lib/rasn1/types/bit_string.rb,
lib/rasn1/types/bmp_string.rb,
lib/rasn1/types/enumerated.rb,
lib/rasn1/types/constrained.rb,
lib/rasn1/types/constructed.rb,
lib/rasn1/types/sequence_of.rb,
lib/rasn1/types/utf8_string.rb,
lib/rasn1/types/octet_string.rb,
lib/rasn1/types/numeric_string.rb,
lib/rasn1/types/visible_string.rb,
lib/rasn1/types/generalized_time.rb,
lib/rasn1/types/printable_string.rb,
lib/rasn1/types/universal_string.rb

Overview

This modules is a namesapce for all ASN.1 type classes.

Author:

  • Sylvain Daubert

Defined Under Namespace

Modules: Constrained Classes: Any, Base, BitString, BmpString, Boolean, Choice, Constructed, Enumerated, GeneralizedTime, IA5String, Integer, Null, NumericString, ObjectId, OctetString, Primitive, PrintableString, Sequence, SequenceOf, Set, SetOf, UniversalString, UtcTime, Utf8String, VisibleString

Class Method Summary collapse

Class Method Details

.constructedArray<Types::Constructed>

Give all constructed types

Returns:



21
22
23
24
25
26
# File 'lib/rasn1/types.rb', line 21

def self.constructed
  return @constructed unless @constructed.empty?

  @constructed = self.constants.map { |c| Types.const_get(c) }
                     .select { |klass| klass < Constructed }
end

.decode_identifier_octets(der) ⇒ Array

Decode a DER string to extract identifier octets.

Parameters:

  • der (String)

Returns:

  • (Array)

    Return ASN.1 class as Symbol, contructed/primitive as Symbol, ID and size of identifier octets



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/rasn1/types.rb', line 33

def self.decode_identifier_octets(der)
  first_octet = der.unpack1('C').to_i
  asn1_class = Types::Base::CLASSES.key(first_octet & Types::Base::CLASS_MASK)
  pc = (first_octet & Types::Constructed::ASN1_PC).positive? ? :constructed : :primitive
  id = first_octet & Types::Base::MULTI_OCTETS_ID

  size = if id == Types::Base::MULTI_OCTETS_ID
           id = 0
           der.bytes.each_with_index do |octet, i|
             next if i.zero?

             id = (id << 7) | (octet & 0x7f)
             break i + 1 if (octet & 0x80).zero?
           end
         else
           1
         end

  [asn1_class, pc, id, size]
end

.define_type(name, from:, in_module: self) {|value| ... } ⇒ Class

Define a new ASN.1 type from a base one. This new type may have a constraint defines on it.

Examples:

# Define a new UInt32 type
# UInt32 ::= INTEGER (0 .. 4294967295)
RASN1::Types.define_type('UInt32', from: RASN1::Types::Integer) do |value|
  (value >= 0) && (value < 2**32)
end

Parameters:

  • name (Symbol, String)

    New type name. Must start with a capital letter.

  • from (Types::Base)

    class from which inherits

  • in_module (Module) (defaults to: self)

    module in which creates new type (default to RASN1::Types)

Yield Parameters:

  • value (Object)

    value to set to type, or infered at parsing

Yield Returns:

Returns:

  • (Class)

    newly created class

Since:

  • 0.11.0

  • 0.12.0 in_module parameter



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/rasn1/types.rb', line 100

def self.define_type(name, from:, in_module: self, &block)
  constraint = block.nil? ? nil : block.to_proc

  new_klass = Class.new(from) do
    include Constrained
  end
  new_klass.constraint = constraint

  in_module.const_set(name, new_klass)
  accel_name = name.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
  Model.define_type_accel(accel_name, new_klass)

  # Empty type caches
  @primitives = []
  @constructed = []

  new_klass
end

.generate_id2type_cacheObject



74
75
76
77
78
79
80
81
82
# File 'lib/rasn1/types.rb', line 74

def self.generate_id2type_cache
  constructed = self.constructed - [Types::SequenceOf, Types::SetOf]
  primitives = self.primitives - [Types::Enumerated]
  ary = (primitives + constructed).select { |type| type.const_defined?(:ID) }
                                  .map { |type| [type.const_get(:ID), type] }
  @id2types = ary.to_h
  @id2types.default = Types::Base
  @id2types.freeze
end

.id2type(der) ⇒ Types::Base

Give ASN.1 type from a DER string. If ID is unknown, return a Base object.

Parameters:

  • der (String)

Returns:

Raises:



59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/rasn1/types.rb', line 59

def self.id2type(der)
  # Define a cache for well-known ASN.1 types
  self.generate_id2type_cache unless defined? @id2types

  asn1class, pc, id, = self.decode_identifier_octets(der)
  # cache_id: check versus class and 5 LSB bits
  cache_id = der.unpack1('C') & 0xdf
  klass = cache_id < Types::Base::MULTI_OCTETS_ID ? @id2types[id] : Types::Base
  is_constructed = (pc == :constructed)
  options = { class: asn1class, constructed: is_constructed }
  options[:tag_value] = id if klass == Types::Base
  klass.new(options)
end

.primitivesArray<Types::Primitive>

Give all primitive types

Returns:



12
13
14
15
16
17
# File 'lib/rasn1/types.rb', line 12

def self.primitives
  return @primitives unless @primitives.empty?

  @primitives = self.constants.map { |c| Types.const_get(c) }
                    .select { |klass| klass < Primitive }
end