From b82ba189903355381570341b054be141d4660a8d Mon Sep 17 00:00:00 2001 From: tenderlove Date: Sat, 11 Dec 2010 17:45:42 +0000 Subject: * ext/openssl/ossl_asn1.c: indefinite length BER to DER encoding is properly supported. Thanks Martin Bosslet! [ruby-core:33082] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@30178 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/openssl/ossl_asn1.c | 147 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 120 insertions(+), 27 deletions(-) (limited to 'ext/openssl/ossl_asn1.c') diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c index add316462f..7fb9121558 100644 --- a/ext/openssl/ossl_asn1.c +++ b/ext/openssl/ossl_asn1.c @@ -19,6 +19,8 @@ struct timeval { }; #endif +static VALUE join_der(VALUE enumerable); + /* * DATE conversion */ @@ -156,15 +158,17 @@ num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai) /* * 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_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_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_infinite_length(o,v) rb_iv_set((o),"@infinite_length",(v)) VALUE mASN1; VALUE eASN1Error; @@ -173,6 +177,7 @@ VALUE cASN1Data; VALUE cASN1Primitive; VALUE cASN1Constructive; +VALUE cASN1EndOfContent; VALUE cASN1Boolean; /* BOOLEAN */ VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */ VALUE cASN1BitString; /* BIT STRING */ @@ -449,7 +454,7 @@ typedef struct { } 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_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE 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_infinite_length(self, Qfalse); return self; } @@ -684,8 +690,8 @@ join_der(VALUE enumerable) 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 @@ ossl_asn1data_to_der(VALUE self) 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 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, long depth, 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 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, long depth, 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 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, long depth, 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_initialize(int argc, VALUE *argv, VALUE self) 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 @@ ossl_asn1prim_to_der(VALUE self) 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(UTCTime) 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 @@ Init_ossl_asn1() 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 @@ do{\ 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 @@ do{\ 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); } -- cgit v1.2.3