static VALUE
ossl_asn1cons_to_der(VALUE self)
{
int tag, tn, tc, explicit, constructed = 1;
int found_prim = 0, seq_len;
long length;
unsigned char *p;
VALUE value, str, inf_length;
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) {
VALUE ary, example;
constructed = 2;
if (CLASS_OF(self) == cASN1Sequence ||
CLASS_OF(self) == cASN1Set) {
tag = ossl_asn1_default_tag(self);
}
else { /* must be a constructive encoding of a primitive value */
ary = ossl_asn1_get_value(self);
if (!rb_obj_is_kind_of(ary, rb_cArray))
ossl_raise(eASN1Error, "Constructive value must be an Array");
/* 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 {
if (CLASS_OF(self) == cASN1Constructive)
ossl_raise(eASN1Error, "Constructive shall only be used with infinite length");
tag = ossl_asn1_default_tag(self);
}
explicit = ossl_asn1_is_explicit(self);
value = join_der(ossl_asn1_get_value(self));
seq_len = ossl_asn1_object_size(constructed, RSTRING_LENINT(value), tag);
length = ossl_asn1_object_size(constructed, seq_len, tn);
str = rb_str_new(0, length);
p = (unsigned char *)RSTRING_PTR(str);
if(tc == V_ASN1_UNIVERSAL)
ossl_asn1_put_object(&p, constructed, RSTRING_LENINT(value), tn, tc);
else{
if(explicit){
ossl_asn1_put_object(&p, constructed, seq_len, tn, tc);
ossl_asn1_put_object(&p, constructed, RSTRING_LENINT(value), tag, V_ASN1_UNIVERSAL);
}
else{
ossl_asn1_put_object(&p, constructed, RSTRING_LENINT(value), tn, tc);
}
}
memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value));
p += RSTRING_LEN(value);
/* In this case we need an additional EOC (one for the explicit part and
* one for the Constructive itself. The EOC for the Constructive is
* supplied by the user, but that for the "explicit wrapper" must be
* added here.
*/
if (explicit && inf_length == Qtrue) {
ASN1_put_eoc(&p);
}
ossl_str_adjust(str, p);
return str;
}