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:



29
30
31
32
33
34
# File 'lib/rasn1/types.rb', line 29

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



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/rasn1/types.rb', line 41

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.anybits?(Types::Constructed::ASN1_PC) ? :constructed : :primitive
  id = first_octet & Types::Base::MULTI_OCTETS_ID

  size = if id == Types::Base::MULTI_OCTETS_ID
           id = 0
           count = 1
           der[1..].to_s.bytes.each do |octet|
             count += 1

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



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/rasn1/types.rb', line 110

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



84
85
86
87
88
89
90
91
92
# File 'lib/rasn1/types.rb', line 84

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:



69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rasn1/types.rb', line 69

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:



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

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

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