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:



23
24
25
26
27
28
# File 'lib/rasn1/types.rb', line 23

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



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

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



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

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



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

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:



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

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:



14
15
16
17
18
19
# File 'lib/rasn1/types.rb', line 14

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

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