Skip to content

Commit 362942d

Browse files
committed
Revert "rewriting most of the asn1 init code in ruby"
This reverts commit 8305051. The commit is part of the bigger effort to rewrite OpenSSL::ASN1 in Ruby. OpenSSL::ASN1 is relatively isolated from the rest of ruby/openssl and is not tightly bound to the OpenSSL API. The current implementation also needs a major refactor for several reasons, so this remains a long-term goal. However, the work is not yet complete. We are close to releasing v4.0.0, and we want to avoid shipping fragmented code in a stable branch. The changes can be reapplied when the rest is ready.
1 parent deb87bf commit 362942d

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)