[前][次][番号順一覧][スレッド一覧]

ruby-changes:18158

From: tenderlove <ko1@a...>
Date: Sun, 12 Dec 2010 02:58:40 +0900 (JST)
Subject: [ruby-changes:18158] Ruby:r30178 (trunk): * ext/openssl/ossl_asn1.c: indefinite length BER to DER encoding is

tenderlove	2010-12-12 02:45:42 +0900 (Sun, 12 Dec 2010)

  New Revision: 30178

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30178

  Log:
    * ext/openssl/ossl_asn1.c: indefinite length BER to DER encoding is
      properly supported.  Thanks Martin Bosslet! [ruby-core:33082]

  Modified files:
    trunk/ChangeLog
    trunk/ext/openssl/ossl_asn1.c
    trunk/test/openssl/test_asn1.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 30177)
+++ ChangeLog	(revision 30178)
@@ -1,3 +1,8 @@
+Sun Dec 12 02:42:24 2010  Aaron Patterson <aaron@t...>
+
+	* ext/openssl/ossl_asn1.c: indefinite length BER to DER encoding is
+	  properly supported.  Thanks Martin Bosslet! [ruby-core:33082]
+
 Sat Dec 11 17:43:34 2010  Kazuhiro NISHIYAMA  <zn@m...>
 
 	* ext/bigdecimal/bigdecimal.h: suppress "warning: 'VPrint' declared
Index: ext/openssl/ossl_asn1.c
===================================================================
--- ext/openssl/ossl_asn1.c	(revision 30177)
+++ ext/openssl/ossl_asn1.c	(revision 30178)
@@ -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,15 +809,39 @@
 		    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{
+                if (tag == V_ASN1_EOC){
+                    asn1data = rb_funcall(cASN1EndOfContent,
+                                          rb_intern("new"),
+                                          0);
+                }
+                else{
+                    asn1data = rb_funcall(klass, rb_intern("new"), 1, value);
+                }
+            }
 	    if(tag == V_ASN1_BIT_STRING){
 		rb_iv_set(asn1data, "@unused_bits", LONG2NUM(flag));
 	    }
 	}
 	else{
-	    asn1data = rb_funcall(cASN1Data, rb_intern("new"), 3,
+            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 +929,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(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 +1013,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 +1166,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 +1202,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 +1249,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 +1258,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, 0);
 }
Index: test/openssl/test_asn1.rb
===================================================================
--- test/openssl/test_asn1.rb	(revision 30177)
+++ test/openssl/test_asn1.rb	(revision 30178)
@@ -203,4 +203,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)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]