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
53
54
# 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) || :universal
  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
           count = 1
           der[1..-1].to_s.bytes.each do |octet|
             count += 1

             id = (id << 7) | (octet & 0x7f)
             break if (octet & 0x80).zero?
           end
           count
         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



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

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

  new_klass = Class.new(from)
  new_klass.include(Constrained)
  new_klass.extend(Constrained::ClassMethods)
  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



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

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:



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

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