1111
1212static VALUE ossl_asn1_decode0 (unsigned char * * pp , long length , long * offset ,
1313 int depth , int yield , long * num_read );
14+ static VALUE ossl_asn1_initialize (int argc , VALUE * argv , VALUE self );
1415
1516/*
1617 * DATE conversion
@@ -199,6 +200,10 @@ ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *obj)
199200#define ossl_asn1_get_tag_class (o ) rb_attr_get((o),sivTAG_CLASS)
200201#define ossl_asn1_get_indefinite_length (o ) rb_attr_get((o),sivINDEFINITE_LENGTH)
201202
203+ #define ossl_asn1_set_value (o ,v ) rb_ivar_set((o),sivVALUE,(v))
204+ #define ossl_asn1_set_tag (o ,v ) rb_ivar_set((o),sivTAG,(v))
205+ #define ossl_asn1_set_tagging (o ,v ) rb_ivar_set((o),sivTAGGING,(v))
206+ #define ossl_asn1_set_tag_class (o ,v ) rb_ivar_set((o),sivTAG_CLASS,(v))
202207#define ossl_asn1_set_indefinite_length (o ,v ) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v))
203208
204209VALUE mASN1 ;
@@ -226,6 +231,7 @@ static VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
226231static VALUE sym_IMPLICIT , sym_EXPLICIT ;
227232static VALUE sym_UNIVERSAL , sym_APPLICATION , sym_CONTEXT_SPECIFIC , sym_PRIVATE ;
228233static ID sivVALUE , sivTAG , sivTAG_CLASS , sivTAGGING , sivINDEFINITE_LENGTH , sivUNUSED_BITS ;
234+ static ID id_each ;
229235
230236/*
231237 * Ruby to ASN1 converters
@@ -669,6 +675,35 @@ ossl_asn1_class2sym(int tc)
669675 return sym_UNIVERSAL ;
670676}
671677
678+ /*
679+ * call-seq:
680+ * OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data
681+ *
682+ * _value_: Please have a look at Constructive and Primitive to see how Ruby
683+ * types are mapped to ASN.1 types and vice versa.
684+ *
685+ * _tag_: An Integer indicating the tag number.
686+ *
687+ * _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for
688+ * possible values.
689+ *
690+ * == Example
691+ * asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)
692+ * tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER
693+ */
694+ static VALUE
695+ ossl_asn1data_initialize (VALUE self , VALUE value , VALUE tag , VALUE tag_class )
696+ {
697+ if (!SYMBOL_P (tag_class ))
698+ ossl_raise (eASN1Error , "invalid tag class" );
699+ ossl_asn1_set_tag (self , tag );
700+ ossl_asn1_set_value (self , value );
701+ ossl_asn1_set_tag_class (self , tag_class );
702+ ossl_asn1_set_indefinite_length (self , Qfalse );
703+
704+ return self ;
705+ }
706+
672707static VALUE
673708to_der_internal (VALUE self , int constructed , int indef_len , VALUE body )
674709{
@@ -797,19 +832,20 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
797832 if (tc == sym_UNIVERSAL &&
798833 tag < ossl_asn1_info_size && ossl_asn1_info [tag ].klass ) {
799834 VALUE klass = * ossl_asn1_info [tag ].klass ;
800- if (tag == V_ASN1_EOC )
801- asn1data = rb_funcall (cASN1EndOfContent , rb_intern ("new" ), 0 );
802- else {
803- VALUE args [4 ] = { value , INT2NUM (tag ), Qnil , tc };
804- asn1data = rb_funcallv_public (klass , rb_intern ("new" ), 4 , args );
805- }
835+ VALUE args [4 ];
836+ args [0 ] = value ;
837+ args [1 ] = INT2NUM (tag );
838+ args [2 ] = Qnil ;
839+ args [3 ] = tc ;
840+ asn1data = rb_obj_alloc (klass );
841+ ossl_asn1_initialize (4 , args , asn1data );
806842 if (tag == V_ASN1_BIT_STRING ){
807843 rb_ivar_set (asn1data , sivUNUSED_BITS , LONG2NUM (flag ));
808844 }
809845 }
810846 else {
811- VALUE args [ 3 ] = { value , INT2NUM ( tag ), tc } ;
812- asn1data = rb_funcallv_public ( cASN1Data , rb_intern ( "new" ), 3 , args );
847+ asn1data = rb_obj_alloc ( cASN1Data ) ;
848+ ossl_asn1data_initialize ( asn1data , value , INT2NUM ( tag ), tc );
813849 }
814850
815851 return asn1data ;
@@ -845,20 +881,20 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
845881 }
846882
847883 if (tc == sym_UNIVERSAL ) {
848- if ( tag == V_ASN1_SEQUENCE ) {
849- VALUE args [ 4 ] = { ary , INT2NUM ( tag ), Qnil , tc };
850- asn1data = rb_funcallv_public ( cASN1Sequence , rb_intern ( "new" ), 4 , args );
851- } else if ( tag == V_ASN1_SET ) {
852- VALUE args [ 4 ] = { ary , INT2NUM ( tag ), Qnil , tc } ;
853- asn1data = rb_funcallv_public ( cASN1Set , rb_intern ( "new" ), 4 , args ) ;
854- } else {
855- VALUE args [4 ] = { ary , INT2NUM ( tag ), Qnil , tc } ;
856- asn1data = rb_funcallv_public ( cASN1Constructive , rb_intern ( "new" ), 4 , args ) ;
857- }
884+ VALUE args [ 4 ];
885+ if ( tag == V_ASN1_SEQUENCE || tag == V_ASN1_SET )
886+ asn1data = rb_obj_alloc ( * ossl_asn1_info [ tag ]. klass );
887+ else
888+ asn1data = rb_obj_alloc ( cASN1Constructive ) ;
889+ args [ 0 ] = ary ;
890+ args [ 1 ] = INT2NUM ( tag );
891+ args [2 ] = Qnil ;
892+ args [ 3 ] = tc ;
893+ ossl_asn1_initialize ( 4 , args , asn1data );
858894 }
859895 else {
860- VALUE args [ 3 ] = { ary , INT2NUM ( tag ), tc } ;
861- asn1data = rb_funcallv_public ( cASN1Data , rb_intern ( "new" ), 3 , args );
896+ asn1data = rb_obj_alloc ( cASN1Data ) ;
897+ ossl_asn1data_initialize ( asn1data , ary , INT2NUM ( tag ), tc );
862898 }
863899
864900 if (indefinite )
@@ -1051,6 +1087,83 @@ ossl_asn1_decode_all(VALUE self, VALUE obj)
10511087 return ary ;
10521088}
10531089
1090+ /*
1091+ * call-seq:
1092+ * OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive
1093+ *
1094+ * _value_: is mandatory.
1095+ *
1096+ * _tag_: optional, may be specified for tagged values. If no _tag_ is
1097+ * specified, the UNIVERSAL tag corresponding to the Primitive sub-class
1098+ * is used by default.
1099+ *
1100+ * _tagging_: may be used as an encoding hint to encode a value either
1101+ * explicitly or implicitly, see ASN1 for possible values.
1102+ *
1103+ * _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to
1104+ * +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then
1105+ * +:CONTEXT_SPECIFIC+ is used as the default. For possible values please
1106+ * cf. ASN1.
1107+ *
1108+ * == Example
1109+ * int = OpenSSL::ASN1::Integer.new(42)
1110+ * zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)
1111+ * private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)
1112+ */
1113+ static VALUE
1114+ ossl_asn1_initialize (int argc , VALUE * argv , VALUE self )
1115+ {
1116+ VALUE value , tag , tagging , tag_class ;
1117+ int default_tag ;
1118+
1119+ rb_scan_args (argc , argv , "13" , & value , & tag , & tagging , & tag_class );
1120+ default_tag = ossl_asn1_default_tag (self );
1121+
1122+ if (default_tag == -1 || argc > 1 ) {
1123+ if (NIL_P (tag ))
1124+ ossl_raise (eASN1Error , "must specify tag number" );
1125+ if (!NIL_P (tagging ) && !SYMBOL_P (tagging ))
1126+ ossl_raise (eASN1Error , "invalid tagging method" );
1127+ if (NIL_P (tag_class )) {
1128+ if (NIL_P (tagging ))
1129+ tag_class = sym_UNIVERSAL ;
1130+ else
1131+ tag_class = sym_CONTEXT_SPECIFIC ;
1132+ }
1133+ if (!SYMBOL_P (tag_class ))
1134+ ossl_raise (eASN1Error , "invalid tag class" );
1135+ }
1136+ else {
1137+ tag = INT2NUM (default_tag );
1138+ tagging = Qnil ;
1139+ tag_class = sym_UNIVERSAL ;
1140+ }
1141+ ossl_asn1_set_tag (self , tag );
1142+ ossl_asn1_set_value (self , value );
1143+ ossl_asn1_set_tagging (self , tagging );
1144+ ossl_asn1_set_tag_class (self , tag_class );
1145+ ossl_asn1_set_indefinite_length (self , Qfalse );
1146+ if (default_tag == V_ASN1_BIT_STRING )
1147+ rb_ivar_set (self , sivUNUSED_BITS , INT2FIX (0 ));
1148+
1149+ return self ;
1150+ }
1151+
1152+ static VALUE
1153+ ossl_asn1eoc_initialize (VALUE self ) {
1154+ VALUE tag , tagging , tag_class , value ;
1155+ tag = INT2FIX (0 );
1156+ tagging = Qnil ;
1157+ tag_class = sym_UNIVERSAL ;
1158+ value = rb_str_new ("" , 0 );
1159+ ossl_asn1_set_tag (self , tag );
1160+ ossl_asn1_set_value (self , value );
1161+ ossl_asn1_set_tagging (self , tagging );
1162+ ossl_asn1_set_tag_class (self , tag_class );
1163+ ossl_asn1_set_indefinite_length (self , Qfalse );
1164+ return self ;
1165+ }
1166+
10541167static VALUE
10551168ossl_asn1eoc_to_der (VALUE self )
10561169{
@@ -1142,6 +1255,27 @@ ossl_asn1cons_to_der(VALUE self)
11421255 return to_der_internal (self , 1 , indef_len , str );
11431256}
11441257
1258+ /*
1259+ * call-seq:
1260+ * asn1_ary.each { |asn1| block } => asn1_ary
1261+ *
1262+ * Calls the given block once for each element in self, passing that element
1263+ * as parameter _asn1_. If no block is given, an enumerator is returned
1264+ * instead.
1265+ *
1266+ * == Example
1267+ * asn1_ary.each do |asn1|
1268+ * puts asn1
1269+ * end
1270+ */
1271+ static VALUE
1272+ ossl_asn1cons_each (VALUE self )
1273+ {
1274+ rb_block_call (ossl_asn1_get_value (self ), id_each , 0 , 0 , 0 , 0 );
1275+
1276+ return self ;
1277+ }
1278+
11451279/*
11461280 * call-seq:
11471281 * OpenSSL::ASN1::ObjectId.register(object_id, short_name, long_name)
@@ -1255,7 +1389,7 @@ ossl_asn1obj_eq(VALUE self, VALUE other)
12551389
12561390#define OSSL_ASN1_IMPL_FACTORY_METHOD (klass ) \
12571391static VALUE ossl_asn1_##klass(int argc, VALUE *argv, VALUE self)\
1258- { return rb_funcallv_public (cASN1##klass, rb_intern("new"), argc, argv); }
1392+ { return rb_funcall3 (cASN1##klass, rb_intern("new"), argc, argv); }
12591393
12601394OSSL_ASN1_IMPL_FACTORY_METHOD (Boolean )
12611395OSSL_ASN1_IMPL_FACTORY_METHOD (Integer )
@@ -1536,6 +1670,42 @@ Init_ossl_asn1(void)
15361670 * puts int2.value # => 1
15371671 */
15381672 cASN1Data = rb_define_class_under (mASN1 , "ASN1Data" , rb_cObject );
1673+ /*
1674+ * Carries the value of a ASN.1 type.
1675+ * Please confer Constructive and Primitive for the mappings between
1676+ * ASN.1 data types and Ruby classes.
1677+ */
1678+ rb_attr (cASN1Data , rb_intern ("value" ), 1 , 1 , 0 );
1679+ /*
1680+ * An Integer representing the tag number of this ASN1Data. Never +nil+.
1681+ */
1682+ rb_attr (cASN1Data , rb_intern ("tag" ), 1 , 1 , 0 );
1683+ /*
1684+ * A Symbol representing the tag class of this ASN1Data. Never +nil+.
1685+ * See ASN1Data for possible values.
1686+ */
1687+ rb_attr (cASN1Data , rb_intern ("tag_class" ), 1 , 1 , 0 );
1688+ /*
1689+ * Never +nil+. A boolean value indicating whether the encoding uses
1690+ * indefinite length (in the case of parsing) or whether an indefinite
1691+ * length form shall be used (in the encoding case).
1692+ * In DER, every value uses definite length form. But in scenarios where
1693+ * large amounts of data need to be transferred it might be desirable to
1694+ * have some kind of streaming support available.
1695+ * For example, huge OCTET STRINGs are preferably sent in smaller-sized
1696+ * chunks, each at a time.
1697+ * This is possible in BER by setting the length bytes of an encoding
1698+ * to zero and by this indicating that the following value will be
1699+ * sent in chunks. Indefinite length encodings are always constructed.
1700+ * The end of such a stream of chunks is indicated by sending a EOC
1701+ * (End of Content) tag. SETs and SEQUENCEs may use an indefinite length
1702+ * encoding, but also primitive types such as e.g. OCTET STRINGS or
1703+ * BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
1704+ */
1705+ rb_attr (cASN1Data , rb_intern ("indefinite_length" ), 1 , 1 , 0 );
1706+ rb_define_alias (cASN1Data , "infinite_length" , "indefinite_length" );
1707+ rb_define_alias (cASN1Data , "infinite_length=" , "indefinite_length=" );
1708+ rb_define_method (cASN1Data , "initialize" , ossl_asn1data_initialize , 3 );
15391709 rb_define_method (cASN1Data , "to_der" , ossl_asn1data_to_der , 0 );
15401710
15411711 /* Document-class: OpenSSL::ASN1::Primitive
@@ -1603,6 +1773,16 @@ Init_ossl_asn1(void)
16031773 * prim_zero_tagged_explicit = <class>.new(value, 0, :EXPLICIT)
16041774 */
16051775 cASN1Primitive = rb_define_class_under (mASN1 , "Primitive" , cASN1Data );
1776+ /*
1777+ * May be used as a hint for encoding a value either implicitly or
1778+ * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
1779+ * _tagging_ is not set when a ASN.1 structure is parsed using
1780+ * OpenSSL::ASN1.decode.
1781+ */
1782+ rb_attr (cASN1Primitive , rb_intern ("tagging" ), 1 , 1 , Qtrue );
1783+ rb_undef_method (cASN1Primitive , "indefinite_length=" );
1784+ rb_undef_method (cASN1Primitive , "infinite_length=" );
1785+ rb_define_method (cASN1Primitive , "initialize" , ossl_asn1_initialize , -1 );
16061786 rb_define_method (cASN1Primitive , "to_der" , ossl_asn1prim_to_der , 0 );
16071787
16081788 /* Document-class: OpenSSL::ASN1::Constructive
@@ -1633,7 +1813,17 @@ Init_ossl_asn1(void)
16331813 * set = OpenSSL::ASN1::Set.new( [ int, str ] )
16341814 */
16351815 cASN1Constructive = rb_define_class_under (mASN1 ,"Constructive" , cASN1Data );
1816+ rb_include_module (cASN1Constructive , rb_mEnumerable );
1817+ /*
1818+ * May be used as a hint for encoding a value either implicitly or
1819+ * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
1820+ * _tagging_ is not set when a ASN.1 structure is parsed using
1821+ * OpenSSL::ASN1.decode.
1822+ */
1823+ rb_attr (cASN1Constructive , rb_intern ("tagging" ), 1 , 1 , Qtrue );
1824+ rb_define_method (cASN1Constructive , "initialize" , ossl_asn1_initialize , -1 );
16361825 rb_define_method (cASN1Constructive , "to_der" , ossl_asn1cons_to_der , 0 );
1826+ rb_define_method (cASN1Constructive , "each" , ossl_asn1cons_each , 0 );
16371827
16381828#define OSSL_ASN1_DEFINE_CLASS (name , super ) \
16391829do{\
@@ -1682,10 +1872,13 @@ do{\
16821872 rb_define_alias (cASN1ObjectId , "short_name" , "sn" );
16831873 rb_define_alias (cASN1ObjectId , "long_name" , "ln" );
16841874 rb_define_method (cASN1ObjectId , "==" , ossl_asn1obj_eq , 1 );
1875+ rb_attr (cASN1BitString , rb_intern ("unused_bits" ), 1 , 1 , 0 );
16851876
1877+ rb_define_method (cASN1EndOfContent , "initialize" , ossl_asn1eoc_initialize , 0 );
16861878 rb_define_method (cASN1EndOfContent , "to_der" , ossl_asn1eoc_to_der , 0 );
16871879
16881880 class_tag_map = rb_hash_new ();
1881+ rb_gc_register_mark_object (class_tag_map );
16891882 rb_hash_aset (class_tag_map , cASN1EndOfContent , INT2NUM (V_ASN1_EOC ));
16901883 rb_hash_aset (class_tag_map , cASN1Boolean , INT2NUM (V_ASN1_BOOLEAN ));
16911884 rb_hash_aset (class_tag_map , cASN1Integer , INT2NUM (V_ASN1_INTEGER ));
@@ -1709,5 +1902,6 @@ do{\
17091902 rb_hash_aset (class_tag_map , cASN1GeneralString , INT2NUM (V_ASN1_GENERALSTRING ));
17101903 rb_hash_aset (class_tag_map , cASN1UniversalString , INT2NUM (V_ASN1_UNIVERSALSTRING ));
17111904 rb_hash_aset (class_tag_map , cASN1BMPString , INT2NUM (V_ASN1_BMPSTRING ));
1712- rb_define_const (mASN1 , "CLASS_TAG_MAP" , class_tag_map );
1905+
1906+ id_each = rb_intern_const ("each" );
17131907}
0 commit comments