Class: RASN1::Types::Base Abstract
- Inherits:
-
Object
- Object
- RASN1::Types::Base
- Defined in:
- lib/rasn1/types/base.rb,
lib/rasn1/tracer.rb
Overview
This is base class for all ASN.1 types.
Subclasses SHOULD define:
-
an ID constant defining ASN.1 BER/DER identification number,
-
a method #der_to_value converting DER into #value.
-
a private method #value_to_der converting its #value to DER,
Define an optional value
An optional value may be defined using :optional key from #initialize:
Integer.new(:int, optional: true)
An optional value implies:
-
while parsing, if decoded ID is not optional expected ID, no ASN1Error is raised, and parser tries next field,
-
while encoding, if #value is
nil, this value is not encoded.
Define a default value
A default value may be defined using :default key from #initialize:
Integer.new(:int, default: 0)
A default value implies:
-
while parsing, if decoded ID is not expected one, no ASN1Error is raised and parser sets default value to this ID. Then parser tries next field,
-
while encoding, if #value is equal to default value, this value is not encoded.
Define a tagged value
ASN.1 permits to define tagged values. By example:
-- context specific tag
CType ::= [0] EXPLICIT INTEGER
-- application specific tag
AType ::= [APPLICATION 1] EXPLICIT INTEGER
-- private tag
PType ::= [PRIVATE 2] EXPLICIT INTEGER
These types may be defined as:
ctype = RASN1::Types::Integer.new(explicit: 0) # with explicit, default #asn1_class is :context
atype = RASN1::Types::Integer.new(explicit: 1, class: :application)
ptype = RASN1::Types::Integer.new(explicit: 2, class: :private)
Sometimes, an EXPLICIT type should be CONSTRUCTED. To do that, use :constructed option:
ptype = RASN1::Types::Integer.new(explicit: 2, class: :private, constructed: true)
Implicit tagged values may also be defined:
ctype_implicit = RASN1::Types::Integer.new(implicit: 0)
Direct Known Subclasses
Any, Choice, Constructed, Primitive, Wrapper::ExplicitWrapper
Constant Summary collapse
- CLASSES =
Allowed ASN.1 classes
{ universal: 0x00, application: 0x40, context: 0x80, private: 0xc0 }.freeze
- CLASS_MASK =
Binary mask to get class
0xc0- MULTI_OCTETS_ID =
0x1f- INDEFINITE_LENGTH =
Length value for indefinite length
0x80
Instance Attribute Summary collapse
- #asn1_class ⇒ Symbol readonly
-
#default ⇒ Object?
readonly
Default value, if defined.
- #name ⇒ String? readonly
- #options ⇒ Hash[Symbol, Object]
Class Method Summary collapse
-
.constrained? ⇒ Booleran
Say if a type is constrained.
-
.encoded_type ⇒ String
Get ASN.1 type used to encode this one.
-
.parse(der_or_ber, options = {}) ⇒ Base
Parse a DER or BER string.
-
.start_tracing ⇒ Object
Patch #do_parse to add tracing ability.
-
.stop_tracing ⇒ Object
Unpatch #do_parse to remove tracing ability.
-
.type ⇒ String
Get ASN.1 type.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
Objects are equal if they have same class AND same DER.
-
#can_build? ⇒ Boolean
Say if DER can be built (not default value, not optional without value, has a value).
-
#constructed? ⇒ ::Boolean
trueif this is a constructed type. -
#der_to_value(der, ber: false) ⇒ void
Make value from DER/BER string.
- #do_parse(der, ber: false) ⇒ Array(::Integer, String)
- #do_parse_explicit(data) ⇒ void
- #do_parse_explicit_with_tracing(data) ⇒ Object
-
#do_parse_with_tracing(der, ber:) ⇒ Object
Parse
derwith tracing abillity. -
#explicit? ⇒ ::Boolean?
Say if a tagged type is explicit.
-
#id ⇒ Integer
Get identifier value.
-
#implicit? ⇒ ::Boolean?
Say if a tagged type is implicit.
-
#initialize(options = {}) ⇒ Base
constructor
A new instance of Base.
-
#initialize_copy ⇒ Object
Deep copy @value and @default.
- #inspect(level = 0) ⇒ String
-
#optional? ⇒ ::Boolean
Say if this type is optional.
-
#parse!(der, ber: false) ⇒ Integer
abstract
Parse a DER string.
-
#primitive? ⇒ ::Boolean
trueif this is a primitive type. - #specific_initializer ⇒ Object abstract
-
#tagged? ⇒ ::Boolean
Say if this type is tagged or not.
-
#to_der ⇒ String
abstract
DER-formated string.
- #trace ⇒ String
-
#type ⇒ String
Get ASN.1 type.
-
#value ⇒ Object
Get value or default value.
-
#value=(val) ⇒ Object
Set value.
-
#value? ⇒ Boolean
Say if a value is set.
-
#value_size ⇒ Integer
Give size in octets of encoded value.
- #void_value ⇒ Object abstract
Constructor Details
#initialize(options = {}) ⇒ Base
Returns a new instance of Base.
132 133 134 135 136 137 138 139 |
# File 'lib/rasn1/types/base.rb', line 132 def initialize(={}) @constructed = nil set_value(.delete(:value)) self. = specific_initializer @raw_data = ''.b @raw_length = ''.b end |
Instance Attribute Details
#asn1_class ⇒ Symbol (readonly)
75 76 77 |
# File 'lib/rasn1/types/base.rb', line 75 def asn1_class @asn1_class end |
#default ⇒ Object? (readonly)
Returns default value, if defined.
77 78 79 |
# File 'lib/rasn1/types/base.rb', line 77 def default @default end |
#name ⇒ String? (readonly)
73 74 75 |
# File 'lib/rasn1/types/base.rb', line 73 def name @name end |
#options ⇒ Hash[Symbol, Object]
79 80 81 |
# File 'lib/rasn1/types/base.rb', line 79 def @options end |
Class Method Details
.constrained? ⇒ Booleran
Say if a type is constrained. Always return false for predefined types
116 117 118 |
# File 'lib/rasn1/types/base.rb', line 116 def self.constrained? false end |
.encoded_type ⇒ String
Get ASN.1 type used to encode this one
97 98 99 |
# File 'lib/rasn1/types/base.rb', line 97 def self.encoded_type type end |
.parse(der_or_ber, options = {}) ⇒ Base
More options are supported. See #initialize.
Parse a DER or BER string
107 108 109 110 111 |
# File 'lib/rasn1/types/base.rb', line 107 def self.parse(der_or_ber, ={}) obj = self.new() obj.parse!(der_or_ber, ber: [:ber]) obj end |
.start_tracing ⇒ Object
Patch #do_parse to add tracing ability
74 75 76 77 78 79 |
# File 'lib/rasn1/tracer.rb', line 74 def start_tracing alias_method :do_parse_without_tracing, :do_parse alias_method :do_parse, :do_parse_with_tracing alias_method :do_parse_explicit_without_tracing, :do_parse_explicit alias_method :do_parse_explicit, :do_parse_explicit_with_tracing end |
.stop_tracing ⇒ Object
Unpatch #do_parse to remove tracing ability
83 84 85 86 |
# File 'lib/rasn1/tracer.rb', line 83 def stop_tracing alias_method :do_parse, :do_parse_without_tracing alias_method :do_parse_explicit, :do_parse_explicit_without_tracing end |
.type ⇒ String
Get ASN.1 type
89 90 91 92 93 |
# File 'lib/rasn1/types/base.rb', line 89 def self.type return @type if defined? @type @type = self.to_s.gsub(/.*::/, '').gsub(/([a-z0-9])([A-Z])/, '\1 \2').upcase end |
Instance Method Details
#==(other) ⇒ Boolean
Objects are equal if they have same class AND same DER
266 267 268 |
# File 'lib/rasn1/types/base.rb', line 266 def ==(other) (other.class == self.class) && (other.to_der == self.to_der) end |
#can_build? ⇒ Boolean
Say if DER can be built (not default value, not optional without value, has a value)
293 294 295 |
# File 'lib/rasn1/types/base.rb', line 293 def can_build? value? && (@default.nil? || (@value != @default)) end |
#constructed? ⇒ ::Boolean
Returns true if this is a constructed type.
211 212 213 |
# File 'lib/rasn1/types/base.rb', line 211 def constructed? (self.class < Constructed) || !!@constructed end |
#der_to_value(der, ber: false) ⇒ void
This method returns an undefined value.
Make value from DER/BER string
341 342 343 |
# File 'lib/rasn1/types/base.rb', line 341 def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument @value = der end |
#do_parse(der, ber: false) ⇒ Array(::Integer, String)
315 316 317 318 319 320 321 322 323 324 |
# File 'lib/rasn1/types/base.rb', line 315 def do_parse(der, ber: false) return [0, ''] unless check_id(der) id_size = Types.decode_identifier_octets(der).last total_length, data = get_data(der[id_size..], ber) total_length += id_size @no_value = false [total_length, data] end |
#do_parse_explicit(data) ⇒ void
This method returns an undefined value.
330 331 332 333 334 |
# File 'lib/rasn1/types/base.rb', line 330 def do_parse_explicit(data) type = explicit_type type.parse!(data) @value = type.value end |
#do_parse_explicit_with_tracing(data) ⇒ Object
98 99 100 101 102 |
# File 'lib/rasn1/tracer.rb', line 98 def do_parse_explicit_with_tracing(data) RASN1.tracer.tracing_level += 1 do_parse_explicit_without_tracing(data) RASN1.tracer.tracing_level -= 1 end |
#do_parse_with_tracing(der, ber:) ⇒ Object
Parse der with tracing abillity
92 93 94 95 96 |
# File 'lib/rasn1/tracer.rb', line 92 def do_parse_with_tracing(der, ber:) ret = do_parse_without_tracing(der, ber: ber) RASN1.tracer.trace(self.trace) ret end |
#explicit? ⇒ ::Boolean?
Say if a tagged type is explicit
187 188 189 |
# File 'lib/rasn1/types/base.rb', line 187 def explicit? defined?(@tag) ? @tag == :explicit : nil # rubocop:disable Style/ReturnNilInPredicateMethodDefinition end |
#id ⇒ Integer
Get identifier value
223 224 225 |
# File 'lib/rasn1/types/base.rb', line 223 def id id_value end |
#implicit? ⇒ ::Boolean?
Say if a tagged type is implicit
194 195 196 |
# File 'lib/rasn1/types/base.rb', line 194 def implicit? defined?(@tag) ? @tag == :implicit : nil # rubocop:disable Style/ReturnNilInPredicateMethodDefinition end |
#initialize_copy ⇒ Object
Deep copy @value and @default.
145 146 147 148 149 150 |
# File 'lib/rasn1/types/base.rb', line 145 def initialize_copy(*) super @value = @value.dup @no_value = @no_value.dup @default = @default.dup end |
#inspect(level = 0) ⇒ String
255 256 257 258 259 260 261 |
# File 'lib/rasn1/types/base.rb', line 255 def inspect(level=0) str = common_inspect(level) str << ' ' << inspect_value str << ' OPTIONAL' if optional? str << " DEFAULT #{@default}" unless @default.nil? str end |
#optional? ⇒ ::Boolean
Say if this type is optional
174 175 176 |
# File 'lib/rasn1/types/base.rb', line 174 def optional? @optional end |
#parse!(der, ber: false) ⇒ Integer
This method SHOULD be partly implemented by subclasses to parse data. Subclasses SHOULD respond to #der_to_value.
Parse a DER string. This method updates object.
234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/rasn1/types/base.rb', line 234 def parse!(der, ber: false) total_length, data = do_parse(der, ber: ber) return 0 if total_length.zero? if explicit? do_parse_explicit(data) else der_to_value(data, ber: ber) end total_length end |
#primitive? ⇒ ::Boolean
Returns true if this is a primitive type.
206 207 208 |
# File 'lib/rasn1/types/base.rb', line 206 def primitive? (self.class < Primitive) && !@constructed end |
#specific_initializer ⇒ Object
To help subclass initialize itself. Default implementation do nothing.
142 |
# File 'lib/rasn1/types/base.rb', line 142 def specific_initializer; end |
#tagged? ⇒ ::Boolean
Say if this type is tagged or not
180 181 182 |
# File 'lib/rasn1/types/base.rb', line 180 def tagged? !@tag.nil? end |
#to_der ⇒ String
This method SHOULD be partly implemented by subclasses, which SHOULD respond to #value_to_der.
Returns DER-formated string.
201 202 203 |
# File 'lib/rasn1/types/base.rb', line 201 def to_der build end |
#trace ⇒ String
299 300 301 302 303 304 305 306 307 308 |
# File 'lib/rasn1/types/base.rb', line 299 def trace return trace_real if value? msg = msg_type if default.nil? # rubocop:disable Style/ConditionalAssignment msg << ' NONE' else msg << " DEFAULT VALUE #{default}" end end |
#type ⇒ String
Get ASN.1 type
217 218 219 |
# File 'lib/rasn1/types/base.rb', line 217 def type self.class.type end |
#value ⇒ Object
Get value or default value
153 154 155 156 157 158 159 |
# File 'lib/rasn1/types/base.rb', line 153 def value if value? @value else @default end end |
#value=(val) ⇒ Object
Set value. If val is nil, unset value
163 164 165 |
# File 'lib/rasn1/types/base.rb', line 163 def value=(val) set_value(val) end |
#value? ⇒ Boolean
Say if a value is set
286 287 288 |
# File 'lib/rasn1/types/base.rb', line 286 def value? !@no_value end |
#value_size ⇒ Integer
Give size in octets of encoded value
249 250 251 |
# File 'lib/rasn1/types/base.rb', line 249 def value_size value_to_der.size end |
#void_value ⇒ Object
Define ‘void’ value (i.e. ‘value’ when no value was set)
168 169 170 |
# File 'lib/rasn1/types/base.rb', line 168 def void_value '' end |