[#33640] [Ruby 1.9-Bug#4136][Open] Enumerable#reject should not inherit the receiver's instance variables — Hiro Asari <redmine@...>

Bug #4136: Enumerable#reject should not inherit the receiver's instance variables

10 messages 2010/12/08

[#33667] [Ruby 1.9-Bug#4149][Open] Documentation submission: syslog standard library — mathew murphy <redmine@...>

Bug #4149: Documentation submission: syslog standard library

11 messages 2010/12/10

[#33683] [feature:trunk] Enumerable#categorize — Tanaka Akira <akr@...>

Hi.

14 messages 2010/12/12
[#33684] Re: [feature:trunk] Enumerable#categorize — "Martin J. Dst" <duerst@...> 2010/12/12

[#33687] Towards a standardized AST for Ruby code — Magnus Holm <judofyr@...>

Hey folks,

23 messages 2010/12/12
[#33688] Re: Towards a standardized AST for Ruby code — Charles Oliver Nutter <headius@...> 2010/12/12

On Sun, Dec 12, 2010 at 9:55 AM, Magnus Holm <judofyr@gmail.com> wrote:

[#33689] Re: Towards a standardized AST for Ruby code — "Haase, Konstantin" <Konstantin.Haase@...> 2010/12/12

On Dec 12, 2010, at 17:46 , Charles Oliver Nutter wrote:

[#33763] [Ruby 1.9-Bug#4168][Open] WeakRef is unsafe to use in Ruby 1.9 — Brian Durand <redmine@...>

Bug #4168: WeakRef is unsafe to use in Ruby 1.9

43 messages 2010/12/17

[#33815] trunk warnflags build issue with curb 0.7.9? — Jon <jon.forums@...>

As this may turn out to be a 3rd party issue rather than a bug, I'd like some feedback.

11 messages 2010/12/22

[#33833] Ruby 1.9.2 is going to be released — "Yuki Sonoda (Yugui)" <yugui@...>

-----BEGIN PGP SIGNED MESSAGE-----

15 messages 2010/12/23

[#33846] [Ruby 1.9-Feature#4197][Open] Improvement of the benchmark library — Benoit Daloze <redmine@...>

Feature #4197: Improvement of the benchmark library

15 messages 2010/12/23

[#33910] [Ruby 1.9-Feature#4211][Open] Converting the Ruby and C API documentation to YARD syntax — Loren Segal <redmine@...>

Feature #4211: Converting the Ruby and C API documentation to YARD syntax

10 messages 2010/12/26

[#33923] [Ruby 1.9-Bug#4214][Open] Fiddle::WINDOWS == false on Windows — Jon Forums <redmine@...>

Bug #4214: Fiddle::WINDOWS == false on Windows

15 messages 2010/12/27

[ruby-core:33501] [Ruby 1.9-Bug#4030] ext/openssl OpenSSL::ASN1::decode / to_der

From: Martin Bosslet <redmine@...>
Date: 2010-12-01 01:56:52 UTC
List: ruby-core #33501
Issue #4030 has been updated by Martin Bosslet.

File asn1_inf_length.diff added

I'd like to propose a patch that would resolve the issue for me.

After analyzing the signatures in more detail I found out that the only BER encodings used were infinite length constructed encodings e.g. for sequence, set and octet string (or bit string) structures. This makes sense in particular for CMS SignedData structures when "attached signatures" are used - encoding the EncapContentInfo using infinite length constructs is the only way to keep streaming support possible.
But the rest of the primitive encodings used DER encoding. Essentially this also means that there is not really a need to cache the entire encoding, it suffices to store the information whether a constructed encoding was encoded with infinite length or not. 
To support this, I added "@infinite length" to each ASN1Data (with getter/setter) that is used to determine the encoding rule to be applied when serializing the object. This is only effective for sub-classes of ASN1Constructive, which is why #infinite_length= is explicitly undefined for all ASN1Primitives. 
Infinite length octet strings and bit strings are represented as ASN1Constructives whose value is an array of octet strings or bit strings respectively, where these again can be constructed, in ASN1Constructive form, or ,ultimately, primitive.
To construct an infinite length encoding from scratch, an instance of the new class OpenSSL::ASN1::EndOfContent must be added at the end of the respective value array.
I also added a couple of tests that assert the expected behavior and also demonstrate the usage of infinite_length.

Best regards,
Martin Boテ殕et
----------------------------------------
http://redmine.ruby-lang.org/issues/show/4030

----------------------------------------
http://redmine.ruby-lang.org

Attachments (1)

asn1_inf_length.diff (18.1 KB, text/x-patch)
Property changes on: ruby/ext/openssl
___________________________________________________________________
Modified: svn:ignore
   - GNUmakefile
Makefile
dep
extconf.h
mkmf.log
openssl.a
conftest.dSYM

   + GNUmakefile
Makefile
dep
extconf.h
mkmf.log
openssl.a
conftest.dSYM
openssl.so


Index: ruby/ext/openssl/ossl_asn1.c
===================================================================
--- ruby/ext/openssl/ossl_asn1.c	(revision 29965)
+++ ruby/ext/openssl/ossl_asn1.c	(working copy)
@@ -19,6 +19,8 @@
 };
 #endif
 
+static VALUE join_der(VALUE enumerable);
+
 /*
  * DATE conversion
  */
@@ -156,15 +158,17 @@
 /*
  * ASN1 module
  */
-#define ossl_asn1_get_value(o)       rb_attr_get((o),rb_intern("@value"))
-#define ossl_asn1_get_tag(o)         rb_attr_get((o),rb_intern("@tag"))
-#define ossl_asn1_get_tagging(o)     rb_attr_get((o),rb_intern("@tagging"))
-#define ossl_asn1_get_tag_class(o)   rb_attr_get((o),rb_intern("@tag_class"))
+#define ossl_asn1_get_value(o)           rb_attr_get((o),rb_intern("@value"))
+#define ossl_asn1_get_tag(o)             rb_attr_get((o),rb_intern("@tag"))
+#define ossl_asn1_get_tagging(o)         rb_attr_get((o),rb_intern("@tagging"))
+#define ossl_asn1_get_tag_class(o)       rb_attr_get((o),rb_intern("@tag_class"))
+#define ossl_asn1_get_infinite_length(o) rb_attr_get((o),rb_intern("@infinite_length"))
 
-#define ossl_asn1_set_value(o,v)     rb_iv_set((o),"@value",(v))
-#define ossl_asn1_set_tag(o,v)       rb_iv_set((o),"@tag",(v))
-#define ossl_asn1_set_tagging(o,v)   rb_iv_set((o),"@tagging",(v))
-#define ossl_asn1_set_tag_class(o,v) rb_iv_set((o),"@tag_class",(v))
+#define ossl_asn1_set_value(o,v)           rb_iv_set((o),"@value",(v))
+#define ossl_asn1_set_tag(o,v)             rb_iv_set((o),"@tag",(v))
+#define ossl_asn1_set_tagging(o,v)         rb_iv_set((o),"@tagging",(v))
+#define ossl_asn1_set_tag_class(o,v)       rb_iv_set((o),"@tag_class",(v))
+#define ossl_asn1_set_infinite_length(o,v) rb_iv_set((o),"@infinite_length",(v))
 
 VALUE mASN1;
 VALUE eASN1Error;
@@ -173,6 +177,7 @@
 VALUE cASN1Primitive;
 VALUE cASN1Constructive;
 
+VALUE cASN1EndOfContent;
 VALUE cASN1Boolean;                           /* BOOLEAN           */
 VALUE cASN1Integer, cASN1Enumerated;          /* INTEGER           */
 VALUE cASN1BitString;                         /* BIT STRING        */
@@ -449,7 +454,7 @@
 } ossl_asn1_info_t;
 
 static ossl_asn1_info_t ossl_asn1_info[] = {
-    { "EOC",               NULL,                  },  /*  0 */
+    { "EOC",               &cASN1EndOfContent,    },  /*  0 */
     { "BOOLEAN",           &cASN1Boolean,         },  /*  1 */
     { "INTEGER",           &cASN1Integer,         },  /*  2 */
     { "BIT_STRING",        &cASN1BitString,       },  /*  3 */
@@ -660,6 +665,7 @@
     ossl_asn1_set_tag(self, tag);
     ossl_asn1_set_value(self, value);
     ossl_asn1_set_tag_class(self, tag_class);
+    ossl_asn1_set_infinite_length(self, Qfalse);
 
     return self;
 }
@@ -684,8 +690,8 @@
 static VALUE
 ossl_asn1data_to_der(VALUE self)
 {
-    VALUE value, der;
-    int tag, tag_class, is_cons = 0;
+    VALUE value, der, inf_length;
+    int tag, tag_class, is_cons = 0, tmp_cons = 1;
     long length;
     unsigned char *p;
 
@@ -698,7 +704,12 @@
 
     tag = ossl_asn1_tag(self);
     tag_class = ossl_asn1_tag_class(self);
-    if((length = ASN1_object_size(1, RSTRING_LEN(value), tag)) <= 0)
+    inf_length = ossl_asn1_get_infinite_length(self);
+    if (inf_length == Qtrue) {
+        is_cons = 2;
+        tmp_cons = 2;
+    }
+    if((length = ASN1_object_size(tmp_cons, RSTRING_LEN(value), tag)) <= 0)
 	ossl_raise(eASN1Error, NULL);
     der = rb_str_new(0, length);
     p = (unsigned char *)RSTRING_PTR(der);
@@ -717,7 +728,7 @@
     unsigned char *start, *p;
     const unsigned char *p0;
     long len, off = *offset;
-    int hlen, tag, tc, j;
+    int hlen, tag, tc, j, infinite = 0;
     VALUE ary, asn1data, value, tag_class;
 
     ary = rb_ary_new();
@@ -752,8 +763,8 @@
 	else
 	    tag_class = sUNIVERSAL;
 	if(j & V_ASN1_CONSTRUCTED){
-	    /* TODO: if j == 0x21 it is indefinite length object. */
 	    if((j == 0x21) && (len == 0)){
+                infinite = 1;
 		long lastoff = off;
 		value = ossl_asn1_decode0(&p, length, &off, depth+1, 0, yield);
 		len = off - lastoff;
@@ -798,7 +809,18 @@
 		    break;
 		}
 	    }
-	    asn1data = rb_funcall(klass, rb_intern("new"), 1, value);
+            if (infinite && !(tag == V_ASN1_SEQUENCE || tag == V_ASN1_SET)){
+                asn1data = rb_funcall(cASN1Constructive,
+                                      rb_intern("new"),
+                                      4,
+                                      value,
+                                      INT2NUM(tag),
+                                      Qnil,
+                                      ID2SYM(tag_class));
+            }
+            else{
+	        asn1data = rb_funcall(klass, rb_intern("new"), 1, value);
+            }
 	    if(tag == V_ASN1_BIT_STRING){
 		rb_iv_set(asn1data, "@unused_bits", LONG2NUM(flag));
 	    }
@@ -807,6 +829,12 @@
 	    asn1data = rb_funcall(cASN1Data, rb_intern("new"), 3,
 				  value, INT2NUM(tag), ID2SYM(tag_class));
 	}
+
+        if (infinite)
+            ossl_asn1_set_infinite_length(asn1data, Qtrue);
+        else
+            ossl_asn1_set_infinite_length(asn1data, Qfalse);
+        
 	rb_ary_push(ary, asn1data);
 	length -= len;
         if(once) break;
@@ -894,10 +922,26 @@
     ossl_asn1_set_value(self, value);
     ossl_asn1_set_tagging(self, tagging);
     ossl_asn1_set_tag_class(self, tag_class);
+    ossl_asn1_set_infinite_length(self, Qfalse);
 
     return self;
 }
 
+static VALUE
+ossl_asn1eoc_initialize(int argc, VALUE *argv, VALUE self) {
+    VALUE tag, tagging, tag_class, value;
+    tag = INT2NUM(ossl_asn1_default_tag(self));
+    tagging = Qnil;
+    tag_class = ID2SYM(sUNIVERSAL);
+    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_infinite_length(self, Qfalse);
+    return self;
+}
+
 static int
 ossl_i2d_ASN1_TYPE(ASN1_TYPE *a, unsigned char **pp)
 {
@@ -962,29 +1006,64 @@
 static VALUE
 ossl_asn1cons_to_der(VALUE self)
 {
-    int tag, tn, tc, explicit;
+    int tag, tn, tc, explicit, constructed = 1;
+    int found_prim = 0;
     long seq_len, length;
     unsigned char *p;
-    VALUE value, str;
+    VALUE value, str, inf_length, ary, example;
 
-    tag = ossl_asn1_default_tag(self);
     tn = NUM2INT(ossl_asn1_get_tag(self));
     tc = ossl_asn1_tag_class(self);
+    inf_length = ossl_asn1_get_infinite_length(self);
+    if (inf_length == Qtrue) {
+        constructed = 2;
+        if (CLASS_OF(self) == cASN1Sequence ||
+            CLASS_OF(self) == cASN1Set) {
+            tag = ossl_asn1_default_tag(self);
+        }
+        else { /*BIT_STRING OR OCTET_STRING*/
+            ary = ossl_asn1_get_value(self);
+            /* Recursively descend until a primitive value is found.
+               The overall value of the entire constructed encoding
+               is of the type of the first primitive encoding to be
+               found. */
+            while (!found_prim){
+                example = rb_ary_entry(ary, 0);
+                if (rb_obj_is_kind_of(example, cASN1Primitive)){
+                    found_prim = 1;
+                }
+                else {
+                    /* example is another ASN1Constructive */
+                    if (!rb_obj_is_kind_of(example, cASN1Constructive)){
+                        ossl_raise(eASN1Error, "invalid constructed encoding");
+                        return Qnil; /* dummy */
+                    }
+                    ary = ossl_asn1_get_value(example);
+                }
+            }
+            tag = ossl_asn1_default_tag(example);
+        }
+    }
+    else {
+        tag = ossl_asn1_default_tag(self);
+    }
     explicit = ossl_asn1_is_explicit(self);
     value = join_der(ossl_asn1_get_value(self));
 
-    seq_len = ASN1_object_size(1, RSTRING_LEN(value), tag);
-    length = ASN1_object_size(1, seq_len, tn);
+    seq_len = ASN1_object_size(constructed, RSTRING_LEN(value), tag);
+    length = ASN1_object_size(constructed, seq_len, tn);
     str = rb_str_new(0, length);
     p = (unsigned char *)RSTRING_PTR(str);
     if(tc == V_ASN1_UNIVERSAL)
-	ASN1_put_object(&p, 1, RSTRING_LEN(value), tn, tc);
+    	ASN1_put_object(&p, constructed, RSTRING_LEN(value), tn, tc);
     else{
 	if(explicit){
-	    ASN1_put_object(&p, 1, seq_len, tn, tc);
-	    ASN1_put_object(&p, 1, RSTRING_LEN(value), tag, V_ASN1_UNIVERSAL);
+    	    ASN1_put_object(&p, constructed, seq_len, tn, tc);
+	    ASN1_put_object(&p, constructed, RSTRING_LEN(value), tag, V_ASN1_UNIVERSAL);
 	}
-	else ASN1_put_object(&p, 1, RSTRING_LEN(value), tn, tc);
+        else{
+            ASN1_put_object(&p, constructed, RSTRING_LEN(value), tn, tc);
+        }
     }
     memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value));
     p += RSTRING_LEN(value);
@@ -1080,6 +1159,7 @@
 OSSL_ASN1_IMPL_FACTORY_METHOD(GeneralizedTime)
 OSSL_ASN1_IMPL_FACTORY_METHOD(Sequence)
 OSSL_ASN1_IMPL_FACTORY_METHOD(Set)
+OSSL_ASN1_IMPL_FACTORY_METHOD(EndOfContent)
 
 void
 Init_ossl_asn1()
@@ -1115,11 +1195,13 @@
     rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0);
     rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0);
     rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0);
+    rb_attr(cASN1Data, rb_intern("infinite_length"), 1, 1, 0);
     rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3);
     rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0);
 
     cASN1Primitive = rb_define_class_under(mASN1, "Primitive", cASN1Data);
     rb_attr(cASN1Primitive, rb_intern("tagging"), 1, 1, Qtrue);
+    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);
 
@@ -1160,6 +1242,8 @@
     OSSL_ASN1_DEFINE_CLASS(Sequence, Constructive);
     OSSL_ASN1_DEFINE_CLASS(Set, Constructive);
 
+    OSSL_ASN1_DEFINE_CLASS(EndOfContent, Data);
+
     rb_define_singleton_method(cASN1ObjectId, "register", ossl_asn1obj_s_register, 3);
     rb_define_method(cASN1ObjectId, "sn", ossl_asn1obj_get_sn, 0);
     rb_define_method(cASN1ObjectId, "ln", ossl_asn1obj_get_ln, 0);
@@ -1167,4 +1251,6 @@
     rb_define_alias(cASN1ObjectId, "short_name", "sn");
     rb_define_alias(cASN1ObjectId, "long_name", "ln");
     rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0);
+
+    rb_define_method(cASN1EndOfContent, "initialize", ossl_asn1eoc_initialize, -1);
 }
Index: ruby/test/openssl/test_asn1.rb
===================================================================
--- ruby/test/openssl/test_asn1.rb	(revision 29965)
+++ ruby/test/openssl/test_asn1.rb	(working copy)
@@ -208,4 +208,231 @@
       assert_equal(v, OpenSSL::ASN1.decode(type.new(v).to_der).value)
     end
   end
+
+  def test_primitive_cannot_set_infinite_length
+    begin
+      prim = OpenSSL::ASN1::Integer.new(50)
+      assert_equal(false, prim.infinite_length)
+      prim.infinite_length = true
+      flunk('Could set infinite length on primitive value')
+    rescue NoMethodError => e
+      #ok
+    end
+  end
+
+  def test_seq_infinite_length
+    begin
+      content = [ OpenSSL::ASN1::Null.new(nil),
+                  OpenSSL::ASN1::EndOfContent.new() ]
+      cons = OpenSSL::ASN1::Sequence.new(content)
+      cons.infinite_length = true
+      expected = %w{ 30 80 05 00 00 00 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, cons.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+
+  def test_set_infinite_length
+    begin
+      content = [ OpenSSL::ASN1::Null.new(nil),
+                  OpenSSL::ASN1::EndOfContent.new() ]
+      cons = OpenSSL::ASN1::Set.new(content)
+      cons.infinite_length = true
+      expected = %w{ 31 80 05 00 00 00 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, cons.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+
+  def test_octet_string_infinite_length
+    begin
+      octets = [ OpenSSL::ASN1::OctetString.new('aaa'),
+                 OpenSSL::ASN1::EndOfContent.new() ]
+      cons = OpenSSL::ASN1::Constructive.new(
+        octets,
+        OpenSSL::ASN1::OCTET_STRING,
+        nil,
+        :UNIVERSAL)
+      cons.infinite_length = true
+      expected = %w{ 24 80 04 03 61 61 61 00 00 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, cons.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+
+  def test_prim_explicit_tagging
+    begin
+      oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT)
+      expected = %w{ A0 03 04 01 61 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, oct_str.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+
+  def test_prim_explicit_tagging_tag_class
+    begin
+      oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT)
+      oct_str2 = OpenSSL::ASN1::OctetString.new(
+        "a",
+        0,
+        :EXPLICIT,
+        :CONTEXT_SPECIFIC)
+      assert_equal(oct_str.to_der, oct_str2.to_der)
+    end
+  end
+
+  def test_prim_implicit_tagging
+    begin
+      int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT)
+      expected = %w{ 80 01 01 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, int.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+
+  def test_prim_implicit_tagging_tag_class
+    begin
+      int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT)
+      int2 = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT, :CONTEXT_SPECIFIC);
+      assert_equal(int.to_der, int2.to_der)
+    end
+  end
+
+  def test_cons_explicit_tagging
+    begin
+      content = [ OpenSSL::ASN1::PrintableString.new('abc') ]
+      seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT)
+      expected = %w{ A2 07 30 05 13 03 61 62 63 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, seq.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+
+  def test_cons_explicit_tagging_inf_length
+    begin
+      content = [ OpenSSL::ASN1::PrintableString.new('abc') ,
+                  OpenSSL::ASN1::EndOfContent.new() ]
+      seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT)
+      seq.infinite_length = true
+      expected = %w{ A2 80 30 80 13 03 61 62 63 00 00 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, seq.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+
+  def test_cons_implicit_tagging
+    begin
+      content = [ OpenSSL::ASN1::Null.new(nil) ]
+      seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT)
+      expected = %w{ A1 02 05 00 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, seq.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+
+  def test_cons_implicit_tagging_inf_length
+    begin
+      content = [ OpenSSL::ASN1::Null.new(nil),
+                  OpenSSL::ASN1::EndOfContent.new() ]
+      seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT)
+      seq.infinite_length = true
+      expected = %w{ A1 80 05 00 00 00 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, seq.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+
+  def test_octet_string_infinite_length_explicit_tagging
+    begin
+      octets = [ OpenSSL::ASN1::OctetString.new('aaa'),
+                 OpenSSL::ASN1::EndOfContent.new() ]
+      cons = OpenSSL::ASN1::Constructive.new(
+        octets,
+        1,
+        :EXPLICIT)
+      cons.infinite_length = true
+      expected = %w{ A1 80 24 80 04 03 61 61 61 00 00 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, cons.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+
+  def test_octet_string_infinite_length_implicit_tagging
+    begin
+      octets = [ OpenSSL::ASN1::OctetString.new('aaa'),
+                 OpenSSL::ASN1::EndOfContent.new() ]
+      cons = OpenSSL::ASN1::Constructive.new(
+        octets,
+        0,
+        :IMPLICIT)
+      cons.infinite_length = true
+      expected = %w{ A0 80 04 03 61 61 61 00 00 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, cons.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+
+  def test_recursive_octet_string_infinite_length
+    begin
+      octets_sub1 = [ OpenSSL::ASN1::OctetString.new("\x01"),
+                      OpenSSL::ASN1::EndOfContent.new() ]
+      octets_sub2 = [ OpenSSL::ASN1::OctetString.new("\x02"),
+                      OpenSSL::ASN1::EndOfContent.new() ]
+      container1 = OpenSSL::ASN1::Constructive.new(
+        octets_sub1,
+        OpenSSL::ASN1::OCTET_STRING,
+        nil,
+        :UNIVERSAL)
+      container1.infinite_length = true
+      container2 = OpenSSL::ASN1::Constructive.new(
+        octets_sub2,
+        OpenSSL::ASN1::OCTET_STRING,
+        nil,
+        :UNIVERSAL)
+      container2.infinite_length = true
+      octets3 = OpenSSL::ASN1::OctetString.new("\x03")
+
+      octets = [ container1, container2, octets3,
+                 OpenSSL::ASN1::EndOfContent.new() ]
+      cons = OpenSSL::ASN1::Constructive.new(
+        octets,
+        OpenSSL::ASN1::OCTET_STRING,
+        nil,
+        :UNIVERSAL)
+      cons.infinite_length = true
+      expected = %w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, cons.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+
+  def test_bit_string_infinite_length
+    begin
+      content = [ OpenSSL::ASN1::BitString.new("\x01"),
+                  OpenSSL::ASN1::EndOfContent.new() ]
+      cons = OpenSSL::ASN1::Constructive.new(
+        content,
+        OpenSSL::ASN1::BIT_STRING,
+        nil,
+        :UNIVERSAL)
+      cons.infinite_length = true
+      expected = %w{ 23 80 03 02 00 01 00 00 }
+      raw = [expected.join('')].pack('H*')
+      assert_equal(raw, cons.to_der)
+      assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
+    end
+  end
+  
 end if defined?(OpenSSL)

In This Thread