aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHoneyryderChuck <cardoso_tiago@hotmail.com>2024-04-16 18:07:56 +0100
committerHoneyryderChuck <cardoso_tiago@hotmail.com>2024-06-17 11:48:34 +0100
commit83050517288250a48accedb7470c9a98a3fe7d51 (patch)
tree23f267d3f72dd0f249c429a62156c29fcdd6aa44
parentc73723443cecdaaf56e12664e51e83f3ecad277c (diff)
downloadruby-openssl-83050517288250a48accedb7470c9a98a3fe7d51.tar.gz
rewriting most of the asn1 init code in ruby
to have as much of the lib in ruby as possible
-rw-r--r--ext/openssl/ossl_asn1.c238
-rw-r--r--ext/openssl/ossl_asn1.h2
-rw-r--r--lib/openssl.rb1
-rw-r--r--lib/openssl/asn1.rb188
4 files changed, 213 insertions, 216 deletions
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
index fb476843..502be101 100644
--- a/ext/openssl/ossl_asn1.c
+++ b/ext/openssl/ossl_asn1.c
@@ -11,7 +11,6 @@
static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset,
int depth, int yield, long *num_read);
-static VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self);
/*
* DATE conversion
@@ -158,10 +157,6 @@ asn1integer_to_num_i(VALUE arg)
#define ossl_asn1_get_tag_class(o) rb_attr_get((o),sivTAG_CLASS)
#define ossl_asn1_get_indefinite_length(o) rb_attr_get((o),sivINDEFINITE_LENGTH)
-#define ossl_asn1_set_value(o,v) rb_ivar_set((o),sivVALUE,(v))
-#define ossl_asn1_set_tag(o,v) rb_ivar_set((o),sivTAG,(v))
-#define ossl_asn1_set_tagging(o,v) rb_ivar_set((o),sivTAGGING,(v))
-#define ossl_asn1_set_tag_class(o,v) rb_ivar_set((o),sivTAG_CLASS,(v))
#define ossl_asn1_set_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v))
VALUE mASN1;
@@ -189,7 +184,6 @@ VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
static VALUE sym_IMPLICIT, sym_EXPLICIT;
static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE;
static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINDEFINITE_LENGTH, sivUNUSED_BITS;
-static ID id_each;
/*
* Ruby to ASN1 converters
@@ -638,35 +632,6 @@ ossl_asn1_class2sym(int tc)
return sym_UNIVERSAL;
}
-/*
- * call-seq:
- * OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data
- *
- * _value_: Please have a look at Constructive and Primitive to see how Ruby
- * types are mapped to ASN.1 types and vice versa.
- *
- * _tag_: An Integer indicating the tag number.
- *
- * _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for
- * possible values.
- *
- * == Example
- * asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)
- * tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER
- */
-static VALUE
-ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class)
-{
- if(!SYMBOL_P(tag_class))
- ossl_raise(eASN1Error, "invalid tag class");
- ossl_asn1_set_tag(self, tag);
- ossl_asn1_set_value(self, value);
- ossl_asn1_set_tag_class(self, tag_class);
- ossl_asn1_set_indefinite_length(self, Qfalse);
-
- return self;
-}
-
static VALUE
to_der_internal(VALUE self, int constructed, int indef_len, VALUE body)
{
@@ -795,20 +760,19 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
if (tc == sym_UNIVERSAL &&
tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) {
VALUE klass = *ossl_asn1_info[tag].klass;
- VALUE args[4];
- args[0] = value;
- args[1] = INT2NUM(tag);
- args[2] = Qnil;
- args[3] = tc;
- asn1data = rb_obj_alloc(klass);
- ossl_asn1_initialize(4, args, asn1data);
+ if (tag == V_ASN1_EOC)
+ asn1data = rb_funcall(cASN1EndOfContent, rb_intern("new"), 0);
+ else {
+ VALUE args[4] = { value, INT2NUM(tag), Qnil, tc };
+ asn1data = rb_funcallv_public(klass, rb_intern("new"), 4, args);
+ }
if(tag == V_ASN1_BIT_STRING){
rb_ivar_set(asn1data, sivUNUSED_BITS, LONG2NUM(flag));
}
}
else {
- asn1data = rb_obj_alloc(cASN1Data);
- ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), tc);
+ VALUE args[3] = { value, INT2NUM(tag), tc };
+ asn1data = rb_funcallv_public(cASN1Data, rb_intern("new"), 3, args);
}
return asn1data;
@@ -842,20 +806,20 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
}
if (tc == sym_UNIVERSAL) {
- VALUE args[4];
- if (tag == V_ASN1_SEQUENCE || tag == V_ASN1_SET)
- asn1data = rb_obj_alloc(*ossl_asn1_info[tag].klass);
- else
- asn1data = rb_obj_alloc(cASN1Constructive);
- args[0] = ary;
- args[1] = INT2NUM(tag);
- args[2] = Qnil;
- args[3] = tc;
- ossl_asn1_initialize(4, args, asn1data);
+ if (tag == V_ASN1_SEQUENCE) {
+ VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
+ asn1data = rb_funcallv_public(cASN1Sequence, rb_intern("new"), 4, args);
+ } else if (tag == V_ASN1_SET) {
+ VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
+ asn1data = rb_funcallv_public(cASN1Set, rb_intern("new"), 4, args);
+ } else {
+ VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
+ asn1data = rb_funcallv_public(cASN1Constructive, rb_intern("new"), 4, args);
+ }
}
else {
- asn1data = rb_obj_alloc(cASN1Data);
- ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), tc);
+ VALUE args[3] = {ary, INT2NUM(tag), tc};
+ asn1data = rb_funcallv_public(cASN1Data, rb_intern("new"), 3, args);
}
if (indefinite)
@@ -1048,83 +1012,6 @@ ossl_asn1_decode_all(VALUE self, VALUE obj)
return ary;
}
-/*
- * call-seq:
- * OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive
- *
- * _value_: is mandatory.
- *
- * _tag_: optional, may be specified for tagged values. If no _tag_ is
- * specified, the UNIVERSAL tag corresponding to the Primitive sub-class
- * is used by default.
- *
- * _tagging_: may be used as an encoding hint to encode a value either
- * explicitly or implicitly, see ASN1 for possible values.
- *
- * _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to
- * +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then
- * +:CONTEXT_SPECIFIC+ is used as the default. For possible values please
- * cf. ASN1.
- *
- * == Example
- * int = OpenSSL::ASN1::Integer.new(42)
- * zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)
- * private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)
- */
-static VALUE
-ossl_asn1_initialize(int argc, VALUE *argv, VALUE self)
-{
- VALUE value, tag, tagging, tag_class;
- int default_tag;
-
- rb_scan_args(argc, argv, "13", &value, &tag, &tagging, &tag_class);
- default_tag = ossl_asn1_default_tag(self);
-
- if (default_tag == -1 || argc > 1) {
- if(NIL_P(tag))
- ossl_raise(eASN1Error, "must specify tag number");
- if(!NIL_P(tagging) && !SYMBOL_P(tagging))
- ossl_raise(eASN1Error, "invalid tagging method");
- if(NIL_P(tag_class)) {
- if (NIL_P(tagging))
- tag_class = sym_UNIVERSAL;
- else
- tag_class = sym_CONTEXT_SPECIFIC;
- }
- if(!SYMBOL_P(tag_class))
- ossl_raise(eASN1Error, "invalid tag class");
- }
- else{
- tag = INT2NUM(default_tag);
- tagging = Qnil;
- tag_class = sym_UNIVERSAL;
- }
- ossl_asn1_set_tag(self, tag);
- ossl_asn1_set_value(self, value);
- ossl_asn1_set_tagging(self, tagging);
- ossl_asn1_set_tag_class(self, tag_class);
- ossl_asn1_set_indefinite_length(self, Qfalse);
- if (default_tag == V_ASN1_BIT_STRING)
- rb_ivar_set(self, sivUNUSED_BITS, INT2FIX(0));
-
- return self;
-}
-
-static VALUE
-ossl_asn1eoc_initialize(VALUE self) {
- VALUE tag, tagging, tag_class, value;
- tag = INT2FIX(0);
- tagging = Qnil;
- tag_class = sym_UNIVERSAL;
- value = rb_str_new("", 0);
- ossl_asn1_set_tag(self, tag);
- ossl_asn1_set_value(self, value);
- ossl_asn1_set_tagging(self, tagging);
- ossl_asn1_set_tag_class(self, tag_class);
- ossl_asn1_set_indefinite_length(self, Qfalse);
- return self;
-}
-
static VALUE
ossl_asn1eoc_to_der(VALUE self)
{
@@ -1218,27 +1105,6 @@ ossl_asn1cons_to_der(VALUE self)
/*
* call-seq:
- * asn1_ary.each { |asn1| block } => asn1_ary
- *
- * Calls the given block once for each element in self, passing that element
- * as parameter _asn1_. If no block is given, an enumerator is returned
- * instead.
- *
- * == Example
- * asn1_ary.each do |asn1|
- * puts asn1
- * end
- */
-static VALUE
-ossl_asn1cons_each(VALUE self)
-{
- rb_block_call(ossl_asn1_get_value(self), id_each, 0, 0, 0, 0);
-
- return self;
-}
-
-/*
- * call-seq:
* OpenSSL::ASN1::ObjectId.register(object_id, short_name, long_name)
*
* This adds a new ObjectId to the internal tables. Where _object_id_ is the
@@ -1371,7 +1237,7 @@ ossl_asn1obj_get_oid(VALUE self)
#define OSSL_ASN1_IMPL_FACTORY_METHOD(klass) \
static VALUE ossl_asn1_##klass(int argc, VALUE *argv, VALUE self)\
-{ return rb_funcall3(cASN1##klass, rb_intern("new"), argc, argv); }
+{ return rb_funcallv_public(cASN1##klass, rb_intern("new"), argc, argv); }
OSSL_ASN1_IMPL_FACTORY_METHOD(Boolean)
OSSL_ASN1_IMPL_FACTORY_METHOD(Integer)
@@ -1657,42 +1523,6 @@ Init_ossl_asn1(void)
* puts int2.value # => 1
*/
cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject);
- /*
- * Carries the value of a ASN.1 type.
- * Please confer Constructive and Primitive for the mappings between
- * ASN.1 data types and Ruby classes.
- */
- rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0);
- /*
- * An Integer representing the tag number of this ASN1Data. Never +nil+.
- */
- rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0);
- /*
- * A Symbol representing the tag class of this ASN1Data. Never +nil+.
- * See ASN1Data for possible values.
- */
- rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0);
- /*
- * Never +nil+. A boolean value indicating whether the encoding uses
- * indefinite length (in the case of parsing) or whether an indefinite
- * length form shall be used (in the encoding case).
- * In DER, every value uses definite length form. But in scenarios where
- * large amounts of data need to be transferred it might be desirable to
- * have some kind of streaming support available.
- * For example, huge OCTET STRINGs are preferably sent in smaller-sized
- * chunks, each at a time.
- * This is possible in BER by setting the length bytes of an encoding
- * to zero and by this indicating that the following value will be
- * sent in chunks. Indefinite length encodings are always constructed.
- * The end of such a stream of chunks is indicated by sending a EOC
- * (End of Content) tag. SETs and SEQUENCEs may use an indefinite length
- * encoding, but also primitive types such as e.g. OCTET STRINGS or
- * BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
- */
- rb_attr(cASN1Data, rb_intern("indefinite_length"), 1, 1, 0);
- rb_define_alias(cASN1Data, "infinite_length", "indefinite_length");
- rb_define_alias(cASN1Data, "infinite_length=", "indefinite_length=");
- rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3);
rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0);
/* Document-class: OpenSSL::ASN1::Primitive
@@ -1760,16 +1590,6 @@ Init_ossl_asn1(void)
* prim_zero_tagged_explicit = <class>.new(value, 0, :EXPLICIT)
*/
cASN1Primitive = rb_define_class_under(mASN1, "Primitive", cASN1Data);
- /*
- * May be used as a hint for encoding a value either implicitly or
- * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
- * _tagging_ is not set when a ASN.1 structure is parsed using
- * OpenSSL::ASN1.decode.
- */
- rb_attr(cASN1Primitive, rb_intern("tagging"), 1, 1, Qtrue);
- rb_undef_method(cASN1Primitive, "indefinite_length=");
- rb_undef_method(cASN1Primitive, "infinite_length=");
- rb_define_method(cASN1Primitive, "initialize", ossl_asn1_initialize, -1);
rb_define_method(cASN1Primitive, "to_der", ossl_asn1prim_to_der, 0);
/* Document-class: OpenSSL::ASN1::Constructive
@@ -1800,17 +1620,7 @@ Init_ossl_asn1(void)
* set = OpenSSL::ASN1::Set.new( [ int, str ] )
*/
cASN1Constructive = rb_define_class_under(mASN1,"Constructive", cASN1Data);
- rb_include_module(cASN1Constructive, rb_mEnumerable);
- /*
- * May be used as a hint for encoding a value either implicitly or
- * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
- * _tagging_ is not set when a ASN.1 structure is parsed using
- * OpenSSL::ASN1.decode.
- */
- rb_attr(cASN1Constructive, rb_intern("tagging"), 1, 1, Qtrue);
- rb_define_method(cASN1Constructive, "initialize", ossl_asn1_initialize, -1);
rb_define_method(cASN1Constructive, "to_der", ossl_asn1cons_to_der, 0);
- rb_define_method(cASN1Constructive, "each", ossl_asn1cons_each, 0);
#define OSSL_ASN1_DEFINE_CLASS(name, super) \
do{\
@@ -1859,13 +1669,10 @@ do{\
rb_define_alias(cASN1ObjectId, "short_name", "sn");
rb_define_alias(cASN1ObjectId, "long_name", "ln");
rb_define_method(cASN1ObjectId, "==", ossl_asn1obj_eq, 1);
- rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0);
- rb_define_method(cASN1EndOfContent, "initialize", ossl_asn1eoc_initialize, 0);
rb_define_method(cASN1EndOfContent, "to_der", ossl_asn1eoc_to_der, 0);
class_tag_map = rb_hash_new();
- rb_gc_register_mark_object(class_tag_map);
rb_hash_aset(class_tag_map, cASN1EndOfContent, INT2NUM(V_ASN1_EOC));
rb_hash_aset(class_tag_map, cASN1Boolean, INT2NUM(V_ASN1_BOOLEAN));
rb_hash_aset(class_tag_map, cASN1Integer, INT2NUM(V_ASN1_INTEGER));
@@ -1889,6 +1696,5 @@ do{\
rb_hash_aset(class_tag_map, cASN1GeneralString, INT2NUM(V_ASN1_GENERALSTRING));
rb_hash_aset(class_tag_map, cASN1UniversalString, INT2NUM(V_ASN1_UNIVERSALSTRING));
rb_hash_aset(class_tag_map, cASN1BMPString, INT2NUM(V_ASN1_BMPSTRING));
-
- id_each = rb_intern_const("each");
+ rb_define_const(mASN1, "CLASS_TAG_MAP", class_tag_map);
}
diff --git a/ext/openssl/ossl_asn1.h b/ext/openssl/ossl_asn1.h
index f47e3539..fae87622 100644
--- a/ext/openssl/ossl_asn1.h
+++ b/ext/openssl/ossl_asn1.h
@@ -55,6 +55,8 @@ extern VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
extern VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
extern VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
+extern VALUE cASN1EndOfContent; /* END OF CONTENT */
+
ASN1_TYPE *ossl_asn1_get_asn1type(VALUE);
void Init_ossl_asn1(void);
diff --git a/lib/openssl.rb b/lib/openssl.rb
index f5ca956d..08899238 100644
--- a/lib/openssl.rb
+++ b/lib/openssl.rb
@@ -13,6 +13,7 @@
require 'openssl.so'
require_relative 'openssl/bn'
+require_relative 'openssl/asn1'
require_relative 'openssl/pkey'
require_relative 'openssl/cipher'
require_relative 'openssl/digest'
diff --git a/lib/openssl/asn1.rb b/lib/openssl/asn1.rb
new file mode 100644
index 00000000..89fa28e1
--- /dev/null
+++ b/lib/openssl/asn1.rb
@@ -0,0 +1,188 @@
+# frozen_string_literal: true
+#--
+#
+# = Ruby-space definitions that completes C-space funcs for ASN.1
+#
+# = Licence
+# This program is licensed under the same licence as Ruby.
+# (See the file 'COPYING'.)
+#++
+
+module OpenSSL
+ module ASN1
+ class ASN1Data
+ #
+ # Carries the value of a ASN.1 type.
+ # Please confer Constructive and Primitive for the mappings between
+ # ASN.1 data types and Ruby classes.
+ #
+ attr_accessor :value
+
+ # An Integer representing the tag number of this ASN1Data. Never +nil+.
+ attr_accessor :tag
+
+ # A Symbol representing the tag class of this ASN1Data. Never +nil+.
+ # See ASN1Data for possible values.
+ attr_accessor :tag_class
+
+ #
+ # Never +nil+. A boolean value indicating whether the encoding uses
+ # indefinite length (in the case of parsing) or whether an indefinite
+ # length form shall be used (in the encoding case).
+ # In DER, every value uses definite length form. But in scenarios where
+ # large amounts of data need to be transferred it might be desirable to
+ # have some kind of streaming support available.
+ # For example, huge OCTET STRINGs are preferably sent in smaller-sized
+ # chunks, each at a time.
+ # This is possible in BER by setting the length bytes of an encoding
+ # to zero and by this indicating that the following value will be
+ # sent in chunks. Indefinite length encodings are always constructed.
+ # The end of such a stream of chunks is indicated by sending a EOC
+ # (End of Content) tag. SETs and SEQUENCEs may use an indefinite length
+ # encoding, but also primitive types such as e.g. OCTET STRINGS or
+ # BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
+ #
+ attr_accessor :indefinite_length
+
+ alias infinite_length indefinite_length
+ alias infinite_length= indefinite_length=
+
+ #
+ # :call-seq:
+ # OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data
+ #
+ # _value_: Please have a look at Constructive and Primitive to see how Ruby
+ # types are mapped to ASN.1 types and vice versa.
+ #
+ # _tag_: An Integer indicating the tag number.
+ #
+ # _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for
+ # possible values.
+ #
+ # == Example
+ # asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)
+ # tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER
+ #
+ def initialize(value, tag, tag_class)
+ raise ASN1Error, "invalid tag class" unless tag_class.is_a?(Symbol)
+
+ @tag = tag
+ @value = value
+ @tag_class = tag_class
+ @indefinite_length = false
+ end
+ end
+
+ module TaggedASN1Data
+ #
+ # May be used as a hint for encoding a value either implicitly or
+ # explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
+ # _tagging_ is not set when a ASN.1 structure is parsed using
+ # OpenSSL::ASN1.decode.
+ #
+ attr_accessor :tagging
+
+ # :call-seq:
+ # OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive
+ #
+ # _value_: is mandatory.
+ #
+ # _tag_: optional, may be specified for tagged values. If no _tag_ is
+ # specified, the UNIVERSAL tag corresponding to the Primitive sub-class
+ # is used by default.
+ #
+ # _tagging_: may be used as an encoding hint to encode a value either
+ # explicitly or implicitly, see ASN1 for possible values.
+ #
+ # _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to
+ # +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then
+ # +:CONTEXT_SPECIFIC+ is used as the default. For possible values please
+ # cf. ASN1.
+ #
+ # == Example
+ # int = OpenSSL::ASN1::Integer.new(42)
+ # zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)
+ # private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)
+ #
+ def initialize(value, tag = nil, tagging = nil, tag_class = nil)
+ tag ||= ASN1.take_default_tag(self.class)
+
+ raise ASN1Error, "must specify tag number" unless tag
+
+ if tagging
+ raise ASN1Error, "invalid tagging method" unless tagging.is_a?(Symbol)
+ end
+
+ tag_class ||= tagging ? :CONTEXT_SPECIFIC : :UNIVERSAL
+
+ raise ASN1Error, "invalid tag class" unless tag_class.is_a?(Symbol)
+
+ @tagging = tagging
+ super(value ,tag, tag_class)
+ end
+ end
+
+ class Primitive < ASN1Data
+ include TaggedASN1Data
+
+ undef_method :indefinite_length=
+ undef_method :infinite_length=
+ end
+
+ class Constructive < ASN1Data
+ include TaggedASN1Data
+ include Enumerable
+
+ # :call-seq:
+ # asn1_ary.each { |asn1| block } => asn1_ary
+ #
+ # Calls the given block once for each element in self, passing that element
+ # as parameter _asn1_. If no block is given, an enumerator is returned
+ # instead.
+ #
+ # == Example
+ # asn1_ary.each do |asn1|
+ # puts asn1
+ # end
+ #
+ def each(&blk)
+ @value.each(&blk)
+
+ self
+ end
+ end
+
+ class Boolean < Primitive ; end
+ class Integer < Primitive ; end
+ class Enumerated < Primitive ; end
+
+ class BitString < Primitive
+ attr_accessor :unused_bits
+
+ def initialize(*)
+ super
+
+ @unused_bits = 0
+ end
+ end
+
+ class EndOfContent < ASN1Data
+ def initialize
+ super("", 0, :UNIVERSAL)
+ end
+ end
+
+ # :nodoc:
+ def self.take_default_tag(klass)
+ tag = CLASS_TAG_MAP[klass]
+
+ return tag if tag
+
+ sklass = klass.superclass
+
+ return unless sklass
+
+ take_default_tag(sklass)
+ end
+ end
+end