Skip to content

Commit 0ace63e

Browse files
authored
Merge pull request #972 from rhenium/ky/asn1-revert-ruby-init
Revert "rewriting most of the asn1 init code in ruby"
2 parents deb87bf + 362942d commit 0ace63e

File tree

3 files changed

+216
-211
lines changed

3 files changed

+216
-211
lines changed

ext/openssl/ossl_asn1.c

Lines changed: 216 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
static 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

204209
VALUE mASN1;
@@ -226,6 +231,7 @@ static VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
226231
static VALUE sym_IMPLICIT, sym_EXPLICIT;
227232
static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE;
228233
static 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+
672707
static VALUE
673708
to_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+
10541167
static VALUE
10551168
ossl_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) \
12571391
static 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

12601394
OSSL_ASN1_IMPL_FACTORY_METHOD(Boolean)
12611395
OSSL_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) \
16391829
do{\
@@ -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
}

lib/openssl.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
require 'openssl.so'
1414

15-
require_relative 'openssl/asn1'
1615
require_relative 'openssl/bn'
1716
require_relative 'openssl/cipher'
1817
require_relative 'openssl/digest'

0 commit comments

Comments
 (0)