Class: RASN2::Types::Base Abstract
- Inherits:
-
Object
- Object
- RASN2::Types::Base
- Includes:
- Helpers::Colorize
- Defined in:
- lib/rasn2/types/base.rb,
lib/rasn2/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:defaultkey 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 = RASN2::Types::Integer.new(explicit: 0) # with explicit, default #asn1_class is :context
atype = RASN2::Types::Integer.new(explicit: 1, class: :application)
ptype = RASN2::Types::Integer.new(explicit: 2, class: :private)
Sometimes, an EXPLICIT type should be CONSTRUCTED. To do that, use
:constructedoption: ptype = RASN2::Types::Integer.new(explicit: 2, class: :private, constructed: true)
Implicit tagged values may also be defined: ctype_implicit = RASN2::Types::Integer.new(implicit: 0)
Direct Known Subclasses
Any, Choice, Constructed, Primitive, Tag, Wrapper::ExplicitWrapper
Constant Summary collapse
- ID =
rubocop:disable Metrics/ClassLength
nil- 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.
-
#model ⇒ Object
Returns the value of attribute model.
- #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.
- #asn1_class_to_s ⇒ Object
- #attributes ⇒ Object
- #bin2hex(str) ⇒ Object
- #build ⇒ Object
-
#can_build? ⇒ Boolean
Say if DER can be built (not default value, not optional without value, has a value).
-
#check_id(der) ⇒ Boolean
Check ID from
deris the one expected. - #colorize(msg) ⇒ Object
- #common_inspect(level = 0, color: false) ⇒ Object
-
#constructed? ⇒ ::Boolean
trueif this is a constructed type. - #der2name(der) ⇒ Object
-
#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. - #encode_identifier_octets ⇒ Object
- #encode_size(size) ⇒ Object
-
#explicit? ⇒ ::Boolean?
Say if a tagged type is explicit.
- #explicit_type ⇒ Object
- #find_type(id) ⇒ Object
- #get_data(der, ber) ⇒ Object
- #get_length(der, ber) ⇒ Object
-
#id ⇒ Integer
Get identifier value.
- #id2octets ⇒ Object
- #id_value ⇒ Object
-
#implicit? ⇒ ::Boolean?
Say if a tagged type is implicit.
- #indent(input, by = 2) ⇒ Object
-
#initialize(options = {}) ⇒ Base
constructor
A new instance of Base.
-
#initialize_copy ⇒ Object
Deep copy @value and @default.
- #inspect(level = 0, color: false) ⇒ String
- #inspect_value ⇒ Object
- #msg_type(raw_id = nil, _encoded_id = nil, no_id: false) ⇒ Object
-
#optional? ⇒ ::Boolean
Say if this type is optional.
-
#parse!(der, ber: false) ⇒ Integer
abstract
Parse a DER string.
- #pc_bit ⇒ Object
-
#primitive? ⇒ ::Boolean
trueif this is a primitive type. - #private? ⇒ Boolean
- #raise_id_error(der) ⇒ Object
- #raise_on_indefinite_length(ber) ⇒ Object
- #self2name ⇒ Object
-
#set_class(asn1_class) ⇒ Object
rubocop:disable Naming/AccessorMethodName.
-
#set_default(default) ⇒ Object
rubocop:disable Naming/AccessorMethodName.
-
#set_optional(optional) ⇒ Object
rubocop:disable Naming/AccessorMethodName.
-
#set_tag(options) ⇒ Object
handle undocumented option
:tag_value, used internally by RASN2.parse to parse non-universal class tags. -
#set_value(value) ⇒ Object
rubocop:disable Naming/AccessorMethodName.
- #specific_initializer ⇒ Object abstract
-
#tag_id_to_integer(value) ⇒ ::Integer
Convert a tag id to an integer.
-
#tagged? ⇒ ::Boolean
Say if this type is tagged or not.
-
#to_der ⇒ String
abstract
DER-formated string.
- #trace ⇒ String
- #trace_data(data = nil) ⇒ Object
- #trace_real ⇒ Object
- #tracer ⇒ Object
-
#type ⇒ String
Get ASN.1 type.
- #universal? ⇒ Boolean
- #unpack(binstr) ⇒ Object
-
#unsigned_to_chained_octets(value) ⇒ Object
Encode an unsigned integer on multiple octets.
-
#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.
- #value_to_der ⇒ Object
- #void_value ⇒ Object abstract
Methods included from Helpers::Colorize
#begin_colorizer, #brace_surround, #colorize_attribute, #colorize_bool, #colorize_class, #colorize_default, #colorize_enum, #colorize_id, #colorize_name, #colorize_nil, #colorize_value, #colorizer, #colorizer=, #end_colorizer, #int_with_hex, #length_specifier, #parens_hex
Constructor Details
#initialize(options = {}) ⇒ Base
Returns a new instance of Base.
140 141 142 143 144 145 146 147 |
# File 'lib/rasn2/types/base.rb', line 140 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)
79 80 81 |
# File 'lib/rasn2/types/base.rb', line 79 def asn1_class @asn1_class end |
#default ⇒ Object? (readonly)
Returns default value, if defined.
81 82 83 |
# File 'lib/rasn2/types/base.rb', line 81 def default @default end |
#model ⇒ Object
Returns the value of attribute model.
50 51 52 |
# File 'lib/rasn2/types/base.rb', line 50 def model @model end |
#name ⇒ String? (readonly)
77 78 79 |
# File 'lib/rasn2/types/base.rb', line 77 def name @name end |
#options ⇒ Hash[Symbol, Object]
83 84 85 |
# File 'lib/rasn2/types/base.rb', line 83 def @options end |
Class Method Details
.constrained? ⇒ Booleran
Say if a type is constrained.
Always return false for predefined types
124 125 126 |
# File 'lib/rasn2/types/base.rb', line 124 def self.constrained? false end |
.encoded_type ⇒ String
Get ASN.1 type used to encode this one
105 106 107 |
# File 'lib/rasn2/types/base.rb', line 105 def self.encoded_type type end |
.parse(der_or_ber, options = {}) ⇒ Base
More options are supported. See #initialize.
Parse a DER or BER string
115 116 117 118 119 |
# File 'lib/rasn2/types/base.rb', line 115 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
95 96 97 98 99 100 |
# File 'lib/rasn2/tracer.rb', line 95 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
104 105 106 107 |
# File 'lib/rasn2/tracer.rb', line 104 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
97 98 99 100 101 |
# File 'lib/rasn2/types/base.rb', line 97 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
307 308 309 |
# File 'lib/rasn2/types/base.rb', line 307 def ==(other) (other.class == self.class) && (other.to_der == self.to_der) end |
#asn1_class_to_s ⇒ Object
416 417 418 |
# File 'lib/rasn2/types/base.rb', line 416 def asn1_class_to_s asn1_class.to_s.upcase end |
#attributes ⇒ Object
265 266 267 268 269 270 271 272 |
# File 'lib/rasn2/types/base.rb', line 265 def attributes attributes = [] attributes << 'OPTIONAL' if optional? attributes << 'CONSTRUCTED' if constructed? && !(self.class < Constructed) attributes << 'EXPLICIT' if explicit? attributes << 'IMPLICIT' if implicit? attributes end |
#bin2hex(str) ⇒ Object
708 709 710 |
# File 'lib/rasn2/types/base.rb', line 708 def bin2hex(str) str.unpack1('H*') end |
#build ⇒ Object
541 542 543 544 545 546 547 548 549 550 551 552 553 554 |
# File 'lib/rasn2/types/base.rb', line 541 def build if can_build? if explicit? v = explicit_type v.value = @value encoded_value = v.to_der else encoded_value = value_to_der end encode_identifier_octets << encode_size(encoded_value.size) << encoded_value else '' end end |
#can_build? ⇒ Boolean
Say if DER can be built (not default value, not optional without value, has a value)
334 335 336 |
# File 'lib/rasn2/types/base.rb', line 334 def can_build? value? && (@default.nil? || (@value != @default)) end |
#check_id(der) ⇒ Boolean
Check ID from der is the one expected
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
# File 'lib/rasn2/types/base.rb', line 607 def check_id(der) # rubocop:disable Naming/PredicateMethod expected_id = encode_identifier_octets real_id = der[0, expected_id.size] return true if real_id == expected_id if optional? @no_value = true @value = void_value elsif !@default.nil? @value = @default else return true if self.instance_of?(Tag) raise_id_error(der) end false end |
#colorize(msg) ⇒ Object
60 61 62 |
# File 'lib/rasn2/types/base.rb', line 60 def colorize(msg) tracer ? tracer.colorize(msg) : self.colorizer.wrap(msg) end |
#common_inspect(level = 0, color: false) ⇒ Object
443 444 445 446 447 448 449 450 451 452 453 454 |
# File 'lib/rasn2/types/base.rb', line 443 def common_inspect(level=0, color: false) begin_colorizer(color) parts = [] parts << "(#{model})" if model parts << colorize_name(name) if name parts << colorize_id(id, asn1_class_to_s) if id && !universal? class_name = colorize_class(type, nil, *self.attributes) class_name += ':' if constructed? parts << class_name end_colorizer "#{" " * level}" + parts.reject(&:empty?).join(' ').to_s end |
#constructed? ⇒ ::Boolean
Returns true if this is a constructed type.
223 224 225 |
# File 'lib/rasn2/types/base.rb', line 223 def constructed? (self.class < Constructed) || !!@constructed end |
#der2name(der) ⇒ Object
692 693 694 695 696 697 698 699 |
# File 'lib/rasn2/types/base.rb', line 692 def der2name(der) return 'no ID' if der.nil? || der.empty? asn1_class, pc, id, id_size = Types.decode_identifier_octets(der) name = "#{asn1_class.to_s.upcase} #{pc.to_s.upcase}" type = find_type(id) name << " #{type.nil? ? bin2hex(der[0...id_size]).to_s : type.encoded_type}" end |
#der_to_value(der, ber: false) ⇒ void
This method returns an undefined value.
Make value from DER/BER string
384 385 386 |
# File 'lib/rasn2/types/base.rb', line 384 def der_to_value(der, ber: false) # rubocop:disable Lint/UnusedMethodArgument @value = der end |
#do_parse(der, ber: false) ⇒ Array(::Integer, String)
358 359 360 361 362 363 364 365 366 367 |
# File 'lib/rasn2/types/base.rb', line 358 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.
373 374 375 376 377 |
# File 'lib/rasn2/types/base.rb', line 373 def do_parse_explicit(data) type = explicit_type type.parse!(data) @value = type.value end |
#do_parse_explicit_with_tracing(data) ⇒ Object
119 120 121 122 123 |
# File 'lib/rasn2/tracer.rb', line 119 def do_parse_explicit_with_tracing(data) tracer.tracing_level += 1 do_parse_explicit_without_tracing(data) tracer.tracing_level -= 1 end |
#do_parse_with_tracing(der, ber:) ⇒ Object
Parse der with tracing abillity
113 114 115 116 117 |
# File 'lib/rasn2/tracer.rb', line 113 def do_parse_with_tracing(der, ber:) ret = do_parse_without_tracing(der, ber: ber) tracer.trace(self.trace) ret end |
#encode_identifier_octets ⇒ Object
562 563 564 |
# File 'lib/rasn2/types/base.rb', line 562 def encode_identifier_octets id2octets.pack('C*') end |
#encode_size(size) ⇒ Object
588 589 590 591 592 593 594 595 596 597 598 599 600 601 |
# File 'lib/rasn2/types/base.rb', line 588 def encode_size(size) if size >= INDEFINITE_LENGTH bytes = [] while size > 255 bytes.unshift(size & 0xff) size >>= 8 end bytes.unshift(size) bytes.unshift(INDEFINITE_LENGTH | bytes.size) bytes.pack('C*') else [size].pack('C') end end |
#explicit? ⇒ ::Boolean?
Say if a tagged type is explicit
195 196 197 |
# File 'lib/rasn2/types/base.rb', line 195 def explicit? defined?(@tag) ? @tag == :explicit : nil # rubocop:disable Style/ReturnNilInPredicateMethodDefinition end |
#explicit_type ⇒ Object
666 667 668 |
# File 'lib/rasn2/types/base.rb', line 666 def explicit_type self.class.new(name: name) end |
#find_type(id) ⇒ Object
701 702 703 704 705 706 |
# File 'lib/rasn2/types/base.rb', line 701 def find_type(id) Types.constants.map { |c| Types.const_get(c) } .grep(Class) .select { |klass| klass < Primitive || klass < Constructed } .find { |klass| id == klass::ID } end |
#get_data(der, ber) ⇒ Object
625 626 627 628 629 630 631 632 633 634 635 636 637 638 |
# File 'lib/rasn2/types/base.rb', line 625 def get_data(der, ber) return [0, ''] if der.nil? || der.empty? length, length_length = get_length(der, ber) data = der[1 + length_length, length] @raw_length = der[0, length_length + 1] @raw_data = data total_length = 1 + length total_length += length_length if length_length.positive? [total_length, data] end |
#get_length(der, ber) ⇒ Object
640 641 642 643 644 645 646 647 648 649 650 651 652 653 |
# File 'lib/rasn2/types/base.rb', line 640 def get_length(der, ber) length = der.unpack1('C').to_i length_length = 0 if length == INDEFINITE_LENGTH raise_on_indefinite_length(ber) elsif length > INDEFINITE_LENGTH length_length = length & 0x7f length = der[1, length_length].unpack('C*') .reduce(0) { |len, b| (len << 8) | b } end [length, length_length] end |
#id ⇒ Integer
Get identifier value
235 236 237 |
# File 'lib/rasn2/types/base.rb', line 235 def id id_value end |
#id2octets ⇒ Object
566 567 568 569 570 571 572 573 |
# File 'lib/rasn2/types/base.rb', line 566 def id2octets first_octet = CLASSES[asn1_class] | pc_bit if id < MULTI_OCTETS_ID [first_octet | id] else [first_octet | MULTI_OCTETS_ID] + unsigned_to_chained_octets(id) end end |
#id_value ⇒ Object
556 557 558 559 560 |
# File 'lib/rasn2/types/base.rb', line 556 def id_value return @id_value if defined?(@id_value) && !@id_value.nil? self.class.const_get(:ID) end |
#implicit? ⇒ ::Boolean?
Say if a tagged type is implicit
202 203 204 |
# File 'lib/rasn2/types/base.rb', line 202 def implicit? defined?(@tag) ? @tag == :implicit : nil # rubocop:disable Style/ReturnNilInPredicateMethodDefinition end |
#indent(input, by = 2) ⇒ Object
688 689 690 |
# File 'lib/rasn2/types/base.rb', line 688 def indent(input, by=2) input.split("\n").map { |line| (" " * by) + line }.join("\n") end |
#initialize_copy ⇒ Object
Deep copy @value and @default.
153 154 155 156 157 158 |
# File 'lib/rasn2/types/base.rb', line 153 def initialize_copy(*) super @value = @value.dup @no_value = @no_value.dup @default = @default.dup end |
#inspect(level = 0, color: false) ⇒ String
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
# File 'lib/rasn2/types/base.rb', line 276 def inspect(level=0, color: false) parts = [] new_level = level.abs + 1 begin_colorizer(color) parts << common_inspect(level, color: color) if constructed? if @value.is_a?(Array) @value.each do |value| parts << "\n" parts << value.inspect(new_level, color: color).to_s end else parts << "\n" if @value.is_a?(Base) parts << @value.inspect(new_level, color: color).to_s else @value.inspect.to_s end end else parts << inspect_value unless inspect_value.empty? end end_colorizer parts.reject(&:empty?).join(' ') end |
#inspect_value ⇒ Object
456 457 458 459 460 461 462 463 464 465 |
# File 'lib/rasn2/types/base.rb', line 456 def inspect_value str = if value? colorize_value(value.inspect) else colorize_nil('(NO VALUE)') end str += colorize_default(@default) if @default str end |
#msg_type(raw_id = nil, _encoded_id = nil, no_id: false) ⇒ Object
420 421 422 423 424 425 426 427 |
# File 'lib/rasn2/types/base.rb', line 420 def msg_type(raw_id=nil, _encoded_id=nil, no_id: false) parts = [] parts << colorize_name(name) unless name.nil? real_id = no_id ? nil : raw_id || id parts << colorize_id(id, asn1_class_to_s) if real_id parts << colorize_class(type, real_id, *self.attributes) parts.reject(&:empty?).join(' ') end |
#optional? ⇒ ::Boolean
Say if this type is optional
182 183 184 |
# File 'lib/rasn2/types/base.rb', line 182 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.
246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/rasn2/types/base.rb', line 246 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 |
#pc_bit ⇒ Object
429 430 431 432 433 434 435 436 437 |
# File 'lib/rasn2/types/base.rb', line 429 def pc_bit if @constructed.nil? self.class.const_get(:ASN1_PC) elsif @constructed # true Constructed::ASN1_PC else # false Primitive::ASN1_PC end end |
#primitive? ⇒ ::Boolean
Returns true if this is a primitive type.
218 219 220 |
# File 'lib/rasn2/types/base.rb', line 218 def primitive? (self.class < Primitive) && !@constructed end |
#private? ⇒ Boolean
206 207 208 |
# File 'lib/rasn2/types/base.rb', line 206 def private? self.instance_of?(Types::Tag) end |
#raise_id_error(der) ⇒ Object
670 671 672 673 674 675 |
# File 'lib/rasn2/types/base.rb', line 670 def raise_id_error(der) msg = name.nil? ? +'' : "#{name}: " msg << "Expected #{self2name} but got #{der2name(der)}" raise ASN1Error, msg end |
#raise_on_indefinite_length(ber) ⇒ Object
655 656 657 658 659 660 661 662 663 664 |
# File 'lib/rasn2/types/base.rb', line 655 def raise_on_indefinite_length(ber) if primitive? raise ASN1Error, "malformed #{type}: indefinite length " \ 'forbidden for primitive types' elsif ber raise NotImplementedError, 'indefinite length not supported' else raise ASN1Error, 'indefinite length forbidden in DER encoding' end end |
#self2name ⇒ Object
677 678 679 680 681 682 683 684 685 686 |
# File 'lib/rasn2/types/base.rb', line 677 def self2name parts = [asn1_class.to_s.upcase] parts << (constructed? ? 'CONSTRUCTED' : 'PRIMITIVE').to_s if implicit? || explicit? parts << '0x%X (0x%s)' % [id, bin2hex(encode_identifier_octets)] else parts << self.class.type.to_s end parts.reject(&:empty?).join(' ') end |
#set_class(asn1_class) ⇒ Object
rubocop:disable Naming/AccessorMethodName
476 477 478 479 480 481 482 483 484 485 486 487 |
# File 'lib/rasn2/types/base.rb', line 476 def set_class(asn1_class) # rubocop:disable Naming/AccessorMethodName case asn1_class when nil @asn1_class = :universal when Symbol raise ClassError unless CLASSES.key?(asn1_class) @asn1_class = asn1_class else raise ClassError end end |
#set_default(default) ⇒ Object
rubocop:disable Naming/AccessorMethodName
493 494 495 |
# File 'lib/rasn2/types/base.rb', line 493 def set_default(default) # rubocop:disable Naming/AccessorMethodName @default = default end |
#set_optional(optional) ⇒ Object
rubocop:disable Naming/AccessorMethodName
489 490 491 |
# File 'lib/rasn2/types/base.rb', line 489 def set_optional(optional) # rubocop:disable Naming/AccessorMethodName @optional = !!optional end |
#set_tag(options) ⇒ Object
handle undocumented option :tag_value, used internally by
RASN2.parse to parse non-universal class tags.
499 500 501 502 503 504 505 506 507 508 509 510 511 512 |
# File 'lib/rasn2/types/base.rb', line 499 def set_tag() # rubocop:disable Naming/AccessorMethodName @constructed = [:constructed] if [:explicit] @tag = :explicit @id_value = tag_id_to_integer([:explicit]) elsif [:implicit] @tag = :implicit @id_value = tag_id_to_integer([:implicit]) elsif [:tag_value] @id_value = tag_id_to_integer([:tag_value]) end @asn1_class = :context if defined?(@tag) && (@asn1_class == :universal) end |
#set_value(value) ⇒ Object
rubocop:disable Naming/AccessorMethodName
530 531 532 533 534 535 536 537 538 539 |
# File 'lib/rasn2/types/base.rb', line 530 def set_value(value) # rubocop:disable Naming/AccessorMethodName if value.nil? @no_value = true @value = void_value else @no_value = false @value = value end value end |
#specific_initializer ⇒ Object
To help subclass initialize itself. Default implementation do nothing.
150 |
# File 'lib/rasn2/types/base.rb', line 150 def specific_initializer; end |
#tag_id_to_integer(value) ⇒ ::Integer
Convert a tag id to an integer. If given a String or Symbol, interprets the characters as big-endian octets (like Apple 4-character codes / 4CCs). Integers are returned as-is.
519 520 521 522 523 524 525 526 527 528 |
# File 'lib/rasn2/types/base.rb', line 519 def tag_id_to_integer(value) case value when ::Integer value when ::String, ::Symbol value.to_s.bytes.reduce(0) { |acc, b| (acc << 8) | b } else value end end |
#tagged? ⇒ ::Boolean
Say if this type is tagged or not
188 189 190 |
# File 'lib/rasn2/types/base.rb', line 188 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.
213 214 215 |
# File 'lib/rasn2/types/base.rb', line 213 def to_der build end |
#trace ⇒ String
340 341 342 343 344 345 346 347 348 349 350 351 |
# File 'lib/rasn2/types/base.rb', line 340 def trace return trace_real if value? parts = [msg_type] parts << if default.nil? colorize_nil else colorize_default(value) end parts.reject(&:empty?).join(' ') end |
#trace_data(data = nil) ⇒ Object
399 400 401 402 403 404 405 406 407 408 409 410 |
# File 'lib/rasn2/types/base.rb', line 399 def trace_data(data=nil) data ||= raw_data format_string = data.size > 65_535 ? '%08X' : '%04X' lines = data.bytes.each_slice(16).map.with_index do |chunk, index| offset = format_string % (index * 16) hex = chunk.map { |b| '%02x' % b }.join(' ') hex_padded = hex.ljust(47) # 16*2 hex digits + 15 spaces ascii = chunk.map { |b| (32..126).cover?(b) ? b.chr : '.' }.join " #{offset} #{hex_padded} |#{ascii}|" end "\n#{lines.join("\n")}" end |
#trace_real ⇒ Object
388 389 390 391 392 393 394 395 396 397 |
# File 'lib/rasn2/types/base.rb', line 388 def trace_real raw_id = encode_identifier_octets encoded_id = raw_id.unpack1('w*') data_length = raw_data.length encoded_length = raw_length.unpack1('w*') parts = [msg_type(raw_id.unpack1('H*').to_i(16), encoded_id)] msg = parts.reject(&:empty?).join(' ') msg << ", #{length_specifier(data_length, encoded_length)}" msg << trace_data end |
#type ⇒ String
Get ASN.1 type
229 230 231 |
# File 'lib/rasn2/types/base.rb', line 229 def type self.class.type end |
#universal? ⇒ Boolean
439 440 441 |
# File 'lib/rasn2/types/base.rb', line 439 def universal? @asn1_class == :universal end |
#unpack(binstr) ⇒ Object
412 413 414 |
# File 'lib/rasn2/types/base.rb', line 412 def unpack(binstr) binstr.unpack1('H*') end |
#unsigned_to_chained_octets(value) ⇒ Object
Encode an unsigned integer on multiple octets. Value is encoded on bit 6-0 of each octet, bit 7(MSB) indicates wether further octets follow.
578 579 580 581 582 583 584 585 586 |
# File 'lib/rasn2/types/base.rb', line 578 def unsigned_to_chained_octets(value) ary = [] while value.positive? ary.unshift(value & 0x7f | 0x80) value >>= 7 end ary[-1] &= 0x7f ary end |
#value ⇒ Object
Get value or default value
161 162 163 164 165 166 167 |
# File 'lib/rasn2/types/base.rb', line 161 def value if value? @value else @default end end |
#value=(val) ⇒ Object
Set value. If val is nil, unset value
171 172 173 |
# File 'lib/rasn2/types/base.rb', line 171 def value=(val) set_value(val) end |
#value? ⇒ Boolean
Say if a value is set
327 328 329 |
# File 'lib/rasn2/types/base.rb', line 327 def value? !@no_value end |
#value_size ⇒ Integer
Give size in octets of encoded value
261 262 263 |
# File 'lib/rasn2/types/base.rb', line 261 def value_size value_to_der.size end |
#value_to_der ⇒ Object
467 468 469 470 471 472 473 474 |
# File 'lib/rasn2/types/base.rb', line 467 def value_to_der case @value when Base @value.to_der else @value.to_s end end |
#void_value ⇒ Object
Define 'void' value (i.e. 'value' when no value was set)
176 177 178 |
# File 'lib/rasn2/types/base.rb', line 176 def void_value '' end |