99 */
1010#include "ossl.h"
1111
12- static VALUE join_der (VALUE enumerable );
1312static VALUE ossl_asn1_decode0 (unsigned char * * pp , long length , long * offset ,
1413 int depth , int yield , long * num_read );
1514static VALUE ossl_asn1_initialize (int argc , VALUE * argv , VALUE self );
@@ -595,20 +594,6 @@ ossl_asn1_tag(VALUE obj)
595594 return NUM2INT (tag );
596595}
597596
598- static int
599- ossl_asn1_is_explicit (VALUE obj )
600- {
601- VALUE s ;
602-
603- s = ossl_asn1_get_tagging (obj );
604- if (NIL_P (s ) || s == sym_IMPLICIT )
605- return 0 ;
606- else if (s == sym_EXPLICIT )
607- return 1 ;
608- else
609- ossl_raise (eASN1Error , "invalid tag default" );
610- }
611-
612597static int
613598ossl_asn1_tag_class (VALUE obj )
614599{
@@ -670,22 +655,50 @@ ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class)
670655}
671656
672657static VALUE
673- join_der_i ( RB_BLOCK_CALL_FUNC_ARGLIST ( i , str ) )
658+ to_der_internal ( VALUE self , int constructed , int indef_len , VALUE body )
674659{
675- i = ossl_to_der_if_possible (i );
676- StringValue (i );
677- rb_str_append (str , i );
678- return Qnil ;
679- }
660+ int encoding = constructed ? indef_len ? 2 : 1 : 0 ;
661+ int tag_class = ossl_asn1_tag_class (self );
662+ int tag_number = ossl_asn1_tag (self );
663+ int default_tag_number = ossl_asn1_default_tag (self );
664+ int body_length , total_length ;
665+ VALUE str ;
666+ unsigned char * p ;
680667
681- static VALUE
682- join_der (VALUE enumerable )
683- {
684- VALUE str = rb_str_new (0 , 0 );
685- rb_block_call (enumerable , id_each , 0 , 0 , join_der_i , str );
668+ body_length = RSTRING_LENINT (body );
669+ if (ossl_asn1_get_tagging (self ) == sym_EXPLICIT ) {
670+ int inner_length , e_encoding = indef_len ? 2 : 1 ;
671+
672+ if (default_tag_number == -1 )
673+ ossl_raise (eASN1Error , "explicit tagging of unknown tag" );
674+
675+ inner_length = ASN1_object_size (encoding , body_length , default_tag_number );
676+ total_length = ASN1_object_size (e_encoding , inner_length , tag_number );
677+ str = rb_str_new (NULL , total_length );
678+ p = (unsigned char * )RSTRING_PTR (str );
679+ /* Put explicit tag */
680+ ASN1_put_object (& p , e_encoding , inner_length , tag_number , tag_class );
681+ /* Append inner object */
682+ ASN1_put_object (& p , encoding , body_length , default_tag_number , V_ASN1_UNIVERSAL );
683+ memcpy (p , RSTRING_PTR (body ), body_length );
684+ p += body_length ;
685+ if (indef_len )
686+ ASN1_put_eoc (& p ); /* For wrapper object */
687+ }
688+ else {
689+ total_length = ASN1_object_size (encoding , body_length , tag_number );
690+ str = rb_str_new (NULL , total_length );
691+ p = (unsigned char * )RSTRING_PTR (str );
692+ ASN1_put_object (& p , encoding , body_length , tag_number , tag_class );
693+ memcpy (p , RSTRING_PTR (body ), body_length );
694+ p += body_length ;
695+ }
696+ ossl_str_adjust (str , p );
686697 return str ;
687698}
688699
700+ static VALUE ossl_asn1prim_to_der (VALUE );
701+ static VALUE ossl_asn1cons_to_der (VALUE );
689702/*
690703 * call-seq:
691704 * asn1.to_der => DER-encoded String
@@ -698,36 +711,16 @@ join_der(VALUE enumerable)
698711static VALUE
699712ossl_asn1data_to_der (VALUE self )
700713{
701- VALUE value , der , inf_length ;
702- int tag , tag_class , is_cons = 0 ;
703- long length ;
704- unsigned char * p ;
714+ VALUE value = ossl_asn1_get_value (self );
705715
706- value = ossl_asn1_get_value (self );
707- if (rb_obj_is_kind_of (value , rb_cArray )){
708- is_cons = 1 ;
709- value = join_der (value );
710- }
711- StringValue (value );
712-
713- tag = ossl_asn1_tag (self );
714- tag_class = ossl_asn1_tag_class (self );
715- inf_length = ossl_asn1_get_indefinite_length (self );
716- if (inf_length == Qtrue ) {
717- if (is_cons == 0 )
718- ossl_raise (eASN1Error , "indefinite form used for primitive encoding" );
719- is_cons = 2 ;
716+ if (rb_obj_is_kind_of (value , rb_cArray ))
717+ return ossl_asn1cons_to_der (self );
718+ else {
719+ if (RTEST (ossl_asn1_get_indefinite_length (self )))
720+ ossl_raise (eASN1Error , "indefinite length form cannot be used " \
721+ "with primitive encoding" );
722+ return ossl_asn1prim_to_der (self );
720723 }
721- if ((length = ASN1_object_size (is_cons , RSTRING_LENINT (value ), tag )) <= 0 )
722- ossl_raise (eASN1Error , NULL );
723- der = rb_str_new (0 , length );
724- p = (unsigned char * )RSTRING_PTR (der );
725- ASN1_put_object (& p , is_cons , RSTRING_LENINT (value ), tag , tag_class );
726- memcpy (p , RSTRING_PTR (value ), RSTRING_LEN (value ));
727- p += RSTRING_LEN (value );
728- ossl_str_adjust (der , p );
729-
730- return der ;
731724}
732725
733726static VALUE
@@ -1115,6 +1108,12 @@ ossl_asn1eoc_initialize(VALUE self) {
11151108 return self ;
11161109}
11171110
1111+ static VALUE
1112+ ossl_asn1eoc_to_der (VALUE self )
1113+ {
1114+ return rb_str_new ("\0\0" , 2 );
1115+ }
1116+
11181117/*
11191118 * call-seq:
11201119 * asn1.to_der => DER-encoded String
@@ -1125,37 +1124,38 @@ static VALUE
11251124ossl_asn1prim_to_der (VALUE self )
11261125{
11271126 ASN1_TYPE * asn1 ;
1128- int tn , tc , explicit ;
1129- long len , reallen ;
1130- unsigned char * buf , * p ;
1127+ long alllen , bodylen ;
1128+ unsigned char * p0 , * p1 ;
1129+ int j , tag , tc , state ;
11311130 VALUE str ;
11321131
1133- tn = ossl_asn1_tag ( self );
1134- tc = ossl_asn1_tag_class (self );
1135- explicit = ossl_asn1_is_explicit ( self );
1136- asn1 = ossl_asn1_get_asn1type ( self );
1132+ if ( ossl_asn1_default_tag ( self ) == -1 ) {
1133+ str = ossl_asn1_get_value (self );
1134+ return to_der_internal ( self , 0 , 0 , StringValue ( str ) );
1135+ }
11371136
1138- len = ASN1_object_size (1 , i2d_ASN1_TYPE (asn1 , NULL ), tn );
1139- if (!(buf = OPENSSL_malloc (len ))){
1137+ asn1 = ossl_asn1_get_asn1type (self );
1138+ alllen = i2d_ASN1_TYPE (asn1 , NULL );
1139+ if (alllen < 0 ) {
11401140 ASN1_TYPE_free (asn1 );
1141- ossl_raise (eASN1Error , "cannot alloc buffer " );
1141+ ossl_raise (eASN1Error , "i2d_ASN1_TYPE " );
11421142 }
1143- p = buf ;
1144- if (tc == V_ASN1_UNIVERSAL ) {
1145- i2d_ASN1_TYPE (asn1 , & p );
1146- } else if (explicit ) {
1147- ASN1_put_object (& p , 1 , i2d_ASN1_TYPE (asn1 , NULL ), tn , tc );
1148- i2d_ASN1_TYPE (asn1 , & p );
1149- } else {
1150- i2d_ASN1_TYPE (asn1 , & p );
1151- * buf = tc | tn | (* buf & V_ASN1_CONSTRUCTED );
1143+ str = ossl_str_new (NULL , alllen , & state );
1144+ if (state ) {
1145+ ASN1_TYPE_free (asn1 );
1146+ rb_jump_tag (state );
11521147 }
1148+ p0 = p1 = (unsigned char * )RSTRING_PTR (str );
1149+ i2d_ASN1_TYPE (asn1 , & p0 );
11531150 ASN1_TYPE_free (asn1 );
1154- reallen = p - buf ;
1155- assert (reallen <= len );
1156- str = ossl_buf2str ((char * )buf , rb_long2int (reallen )); /* buf will be free in ossl_buf2str */
1151+ assert (p0 - p1 == alllen );
11571152
1158- return str ;
1153+ /* Strip header since to_der_internal() wants only the payload */
1154+ j = ASN1_get_object ((const unsigned char * * )& p1 , & bodylen , & tag , & tc , alllen );
1155+ if (j & 0x80 )
1156+ ossl_raise (eASN1Error , "ASN1_get_object" ); /* should not happen */
1157+
1158+ return to_der_internal (self , 0 , 0 , rb_str_drop_bytes (str , alllen - bodylen ));
11591159}
11601160
11611161/*
@@ -1167,59 +1167,22 @@ ossl_asn1prim_to_der(VALUE self)
11671167static VALUE
11681168ossl_asn1cons_to_der (VALUE self )
11691169{
1170- int tn , tc , explicit , constructed , value_length ;
1171- unsigned char * p ;
1172- VALUE value , str , inf_length ;
1173-
1174- tn = ossl_asn1_tag (self );
1175- tc = ossl_asn1_tag_class (self );
1176- inf_length = ossl_asn1_get_indefinite_length (self );
1177- explicit = ossl_asn1_is_explicit (self );
1178- value = join_der (ossl_asn1_get_value (self ));
1179- value_length = RSTRING_LENINT (value );
1180- constructed = RTEST (inf_length ) ? 2 : 1 ;
1181-
1182- if (explicit ) {
1183- int length , inner_length , default_tag ;
1184-
1185- default_tag = ossl_asn1_default_tag (self );
1186- /*
1187- * non-universal tag class class && explicit tagging; this is not
1188- * possible because the inner tag number is unknown.
1189- */
1190- if (default_tag == -1 )
1191- ossl_raise (eASN1Error , "explicit tagging of unknown tag" );
1192-
1193- inner_length = ASN1_object_size (constructed , value_length , default_tag );
1194- length = ASN1_object_size (constructed , inner_length , tn );
1195- str = rb_str_new (0 , length );
1196- p = (unsigned char * )RSTRING_PTR (str );
1197- ASN1_put_object (& p , constructed , inner_length , tn , tc );
1198- ASN1_put_object (& p , constructed , value_length , default_tag , V_ASN1_UNIVERSAL );
1199- }
1200- else {
1201- int length ;
1202-
1203- length = ASN1_object_size (constructed , value_length , tn );
1204- str = rb_str_new (0 , length );
1205- p = (unsigned char * )RSTRING_PTR (str );
1206- ASN1_put_object (& p , constructed , value_length , tn , tc );
1170+ VALUE ary , str ;
1171+ long i ;
1172+ int indef_len ;
1173+
1174+ indef_len = RTEST (ossl_asn1_get_indefinite_length (self ));
1175+ ary = rb_convert_type (ossl_asn1_get_value (self ), T_ARRAY , "Array" , "to_a" );
1176+ str = rb_str_new (NULL , 0 );
1177+ for (i = 0 ; i < RARRAY_LEN (ary ); i ++ ) {
1178+ VALUE item = RARRAY_AREF (ary , i );
1179+
1180+ item = ossl_to_der_if_possible (item );
1181+ StringValue (item );
1182+ rb_str_append (str , item );
12071183 }
12081184
1209- memcpy (p , RSTRING_PTR (value ), value_length );
1210- p += value_length ;
1211-
1212- /* In this case we need an additional EOC (one for the explicit part and
1213- * one for the Constructive itself. The EOC for the Constructive is
1214- * supplied by the user, but that for the "explicit wrapper" must be
1215- * added here.
1216- */
1217- if (explicit && RTEST (inf_length )) {
1218- ASN1_put_eoc (& p );
1219- }
1220- ossl_str_adjust (str , p );
1221-
1222- return str ;
1185+ return to_der_internal (self , 1 , indef_len , str );
12231186}
12241187
12251188/*
@@ -1842,6 +1805,7 @@ do{\
18421805 rb_attr (cASN1BitString , rb_intern ("unused_bits" ), 1 , 1 , 0 );
18431806
18441807 rb_define_method (cASN1EndOfContent , "initialize" , ossl_asn1eoc_initialize , 0 );
1808+ rb_define_method (cASN1EndOfContent , "to_der" , ossl_asn1eoc_to_der , 0 );
18451809
18461810 class_tag_map = rb_hash_new ();
18471811 rb_hash_aset (class_tag_map , cASN1EndOfContent , INT2NUM (V_ASN1_EOC ));
0 commit comments