Skip to content

Commit bbacdfa

Browse files
rewriting most of the asn1 init code in ruby
to have as much of the lib in ruby as possible
1 parent c737234 commit bbacdfa

File tree

4 files changed

+218
-221
lines changed

4 files changed

+218
-221
lines changed

ext/openssl/ossl_asn1.c

Lines changed: 27 additions & 221 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
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);
1514

1615
/*
1716
* DATE conversion
@@ -158,10 +157,6 @@ asn1integer_to_num_i(VALUE arg)
158157
#define ossl_asn1_get_tag_class(o) rb_attr_get((o),sivTAG_CLASS)
159158
#define ossl_asn1_get_indefinite_length(o) rb_attr_get((o),sivINDEFINITE_LENGTH)
160159

161-
#define ossl_asn1_set_value(o,v) rb_ivar_set((o),sivVALUE,(v))
162-
#define ossl_asn1_set_tag(o,v) rb_ivar_set((o),sivTAG,(v))
163-
#define ossl_asn1_set_tagging(o,v) rb_ivar_set((o),sivTAGGING,(v))
164-
#define ossl_asn1_set_tag_class(o,v) rb_ivar_set((o),sivTAG_CLASS,(v))
165160
#define ossl_asn1_set_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v))
166161

167162
VALUE mASN1;
@@ -189,7 +184,6 @@ VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
189184
static VALUE sym_IMPLICIT, sym_EXPLICIT;
190185
static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE;
191186
static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINDEFINITE_LENGTH, sivUNUSED_BITS;
192-
static ID id_each;
193187

194188
/*
195189
* Ruby to ASN1 converters
@@ -638,35 +632,6 @@ ossl_asn1_class2sym(int tc)
638632
return sym_UNIVERSAL;
639633
}
640634

641-
/*
642-
* call-seq:
643-
* OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data
644-
*
645-
* _value_: Please have a look at Constructive and Primitive to see how Ruby
646-
* types are mapped to ASN.1 types and vice versa.
647-
*
648-
* _tag_: An Integer indicating the tag number.
649-
*
650-
* _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for
651-
* possible values.
652-
*
653-
* == Example
654-
* asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)
655-
* tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER
656-
*/
657-
static VALUE
658-
ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class)
659-
{
660-
if(!SYMBOL_P(tag_class))
661-
ossl_raise(eASN1Error, "invalid tag class");
662-
ossl_asn1_set_tag(self, tag);
663-
ossl_asn1_set_value(self, value);
664-
ossl_asn1_set_tag_class(self, tag_class);
665-
ossl_asn1_set_indefinite_length(self, Qfalse);
666-
667-
return self;
668-
}
669-
670635
static VALUE
671636
to_der_internal(VALUE self, int constructed, int indef_len, VALUE body)
672637
{
@@ -795,23 +760,22 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
795760
if (tc == sym_UNIVERSAL &&
796761
tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) {
797762
VALUE klass = *ossl_asn1_info[tag].klass;
798-
VALUE args[4];
799-
args[0] = value;
800-
args[1] = INT2NUM(tag);
801-
args[2] = Qnil;
802-
args[3] = tc;
803-
asn1data = rb_obj_alloc(klass);
804-
ossl_asn1_initialize(4, args, asn1data);
763+
if (tag == V_ASN1_EOC)
764+
asn1data = rb_funcall(cASN1EndOfContent, rb_intern("new"), 0);
765+
else {
766+
VALUE args[4] = { value, INT2NUM(tag), Qnil, tc };
767+
asn1data = rb_funcallv_public(klass, rb_intern("new"), 4, args);
768+
}
805769
if(tag == V_ASN1_BIT_STRING){
806-
rb_ivar_set(asn1data, sivUNUSED_BITS, LONG2NUM(flag));
770+
rb_ivar_set(asn1data, sivUNUSED_BITS, LONG2NUM(flag));
807771
}
808-
}
809-
else {
810-
asn1data = rb_obj_alloc(cASN1Data);
811-
ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), tc);
812-
}
772+
}
773+
else {
774+
VALUE args[3] = { value, INT2NUM(tag), tc };
775+
asn1data = rb_funcallv_public(cASN1Data, rb_intern("new"), 3, args);
776+
}
813777

814-
return asn1data;
778+
return asn1data;
815779
}
816780

817781
static VALUE
@@ -842,20 +806,20 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
842806
}
843807

844808
if (tc == sym_UNIVERSAL) {
845-
VALUE args[4];
846-
if (tag == V_ASN1_SEQUENCE || tag == V_ASN1_SET)
847-
asn1data = rb_obj_alloc(*ossl_asn1_info[tag].klass);
848-
else
849-
asn1data = rb_obj_alloc(cASN1Constructive);
850-
args[0] = ary;
851-
args[1] = INT2NUM(tag);
852-
args[2] = Qnil;
853-
args[3] = tc;
854-
ossl_asn1_initialize(4, args, asn1data);
855-
}
809+
if (tag == V_ASN1_SEQUENCE) {
810+
VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
811+
asn1data = rb_funcall3(cASN1Sequence, rb_intern("new"), 4, args);
812+
} else if (tag == V_ASN1_SET) {
813+
VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
814+
asn1data = rb_funcall3(cASN1Set, rb_intern("new"), 4, args);
815+
} else {
816+
VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
817+
asn1data = rb_funcall3(cASN1Constructive, rb_intern("new"), 4, args);
818+
}
819+
}
856820
else {
857-
asn1data = rb_obj_alloc(cASN1Data);
858-
ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), tc);
821+
VALUE args[3] = {ary, INT2NUM(tag), tc};
822+
asn1data = rb_funcall3(cASN1Data, rb_intern("new"), 3, args);
859823
}
860824

861825
if (indefinite)
@@ -1048,83 +1012,6 @@ ossl_asn1_decode_all(VALUE self, VALUE obj)
10481012
return ary;
10491013
}
10501014

1051-
/*
1052-
* call-seq:
1053-
* OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive
1054-
*
1055-
* _value_: is mandatory.
1056-
*
1057-
* _tag_: optional, may be specified for tagged values. If no _tag_ is
1058-
* specified, the UNIVERSAL tag corresponding to the Primitive sub-class
1059-
* is used by default.
1060-
*
1061-
* _tagging_: may be used as an encoding hint to encode a value either
1062-
* explicitly or implicitly, see ASN1 for possible values.
1063-
*
1064-
* _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to
1065-
* +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then
1066-
* +:CONTEXT_SPECIFIC+ is used as the default. For possible values please
1067-
* cf. ASN1.
1068-
*
1069-
* == Example
1070-
* int = OpenSSL::ASN1::Integer.new(42)
1071-
* zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)
1072-
* private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)
1073-
*/
1074-
static VALUE
1075-
ossl_asn1_initialize(int argc, VALUE *argv, VALUE self)
1076-
{
1077-
VALUE value, tag, tagging, tag_class;
1078-
int default_tag;
1079-
1080-
rb_scan_args(argc, argv, "13", &value, &tag, &tagging, &tag_class);
1081-
default_tag = ossl_asn1_default_tag(self);
1082-
1083-
if (default_tag == -1 || argc > 1) {
1084-
if(NIL_P(tag))
1085-
ossl_raise(eASN1Error, "must specify tag number");
1086-
if(!NIL_P(tagging) && !SYMBOL_P(tagging))
1087-
ossl_raise(eASN1Error, "invalid tagging method");
1088-
if(NIL_P(tag_class)) {
1089-
if (NIL_P(tagging))
1090-
tag_class = sym_UNIVERSAL;
1091-
else
1092-
tag_class = sym_CONTEXT_SPECIFIC;
1093-
}
1094-
if(!SYMBOL_P(tag_class))
1095-
ossl_raise(eASN1Error, "invalid tag class");
1096-
}
1097-
else{
1098-
tag = INT2NUM(default_tag);
1099-
tagging = Qnil;
1100-
tag_class = sym_UNIVERSAL;
1101-
}
1102-
ossl_asn1_set_tag(self, tag);
1103-
ossl_asn1_set_value(self, value);
1104-
ossl_asn1_set_tagging(self, tagging);
1105-
ossl_asn1_set_tag_class(self, tag_class);
1106-
ossl_asn1_set_indefinite_length(self, Qfalse);
1107-
if (default_tag == V_ASN1_BIT_STRING)
1108-
rb_ivar_set(self, sivUNUSED_BITS, INT2FIX(0));
1109-
1110-
return self;
1111-
}
1112-
1113-
static VALUE
1114-
ossl_asn1eoc_initialize(VALUE self) {
1115-
VALUE tag, tagging, tag_class, value;
1116-
tag = INT2FIX(0);
1117-
tagging = Qnil;
1118-
tag_class = sym_UNIVERSAL;
1119-
value = rb_str_new("", 0);
1120-
ossl_asn1_set_tag(self, tag);
1121-
ossl_asn1_set_value(self, value);
1122-
ossl_asn1_set_tagging(self, tagging);
1123-
ossl_asn1_set_tag_class(self, tag_class);
1124-
ossl_asn1_set_indefinite_length(self, Qfalse);
1125-
return self;
1126-
}
1127-
11281015
static VALUE
11291016
ossl_asn1eoc_to_der(VALUE self)
11301017
{
@@ -1216,27 +1103,6 @@ ossl_asn1cons_to_der(VALUE self)
12161103
return to_der_internal(self, 1, indef_len, str);
12171104
}
12181105

1219-
/*
1220-
* call-seq:
1221-
* asn1_ary.each { |asn1| block } => asn1_ary
1222-
*
1223-
* Calls the given block once for each element in self, passing that element
1224-
* as parameter _asn1_. If no block is given, an enumerator is returned
1225-
* instead.
1226-
*
1227-
* == Example
1228-
* asn1_ary.each do |asn1|
1229-
* puts asn1
1230-
* end
1231-
*/
1232-
static VALUE
1233-
ossl_asn1cons_each(VALUE self)
1234-
{
1235-
rb_block_call(ossl_asn1_get_value(self), id_each, 0, 0, 0, 0);
1236-
1237-
return self;
1238-
}
1239-
12401106
/*
12411107
* call-seq:
12421108
* OpenSSL::ASN1::ObjectId.register(object_id, short_name, long_name)
@@ -1657,42 +1523,6 @@ Init_ossl_asn1(void)
16571523
* puts int2.value # => 1
16581524
*/
16591525
cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject);
1660-
/*
1661-
* Carries the value of a ASN.1 type.
1662-
* Please confer Constructive and Primitive for the mappings between
1663-
* ASN.1 data types and Ruby classes.
1664-
*/
1665-
rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0);
1666-
/*
1667-
* An Integer representing the tag number of this ASN1Data. Never +nil+.
1668-
*/
1669-
rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0);
1670-
/*
1671-
* A Symbol representing the tag class of this ASN1Data. Never +nil+.
1672-
* See ASN1Data for possible values.
1673-
*/
1674-
rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0);
1675-
/*
1676-
* Never +nil+. A boolean value indicating whether the encoding uses
1677-
* indefinite length (in the case of parsing) or whether an indefinite
1678-
* length form shall be used (in the encoding case).
1679-
* In DER, every value uses definite length form. But in scenarios where
1680-
* large amounts of data need to be transferred it might be desirable to
1681-
* have some kind of streaming support available.
1682-
* For example, huge OCTET STRINGs are preferably sent in smaller-sized
1683-
* chunks, each at a time.
1684-
* This is possible in BER by setting the length bytes of an encoding
1685-
* to zero and by this indicating that the following value will be
1686-
* sent in chunks. Indefinite length encodings are always constructed.
1687-
* The end of such a stream of chunks is indicated by sending a EOC
1688-
* (End of Content) tag. SETs and SEQUENCEs may use an indefinite length
1689-
* encoding, but also primitive types such as e.g. OCTET STRINGS or
1690-
* BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
1691-
*/
1692-
rb_attr(cASN1Data, rb_intern("indefinite_length"), 1, 1, 0);
1693-
rb_define_alias(cASN1Data, "infinite_length", "indefinite_length");
1694-
rb_define_alias(cASN1Data, "infinite_length=", "indefinite_length=");
1695-
rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3);
16961526
rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0);
16971527

16981528
/* Document-class: OpenSSL::ASN1::Primitive
@@ -1760,16 +1590,6 @@ Init_ossl_asn1(void)
17601590
* prim_zero_tagged_explicit = <class>.new(value, 0, :EXPLICIT)
17611591
*/
17621592
cASN1Primitive = rb_define_class_under(mASN1, "Primitive", cASN1Data);
1763-
/*
1764-
* May be used as a hint for encoding a value either implicitly or
1765-
* explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
1766-
* _tagging_ is not set when a ASN.1 structure is parsed using
1767-
* OpenSSL::ASN1.decode.
1768-
*/
1769-
rb_attr(cASN1Primitive, rb_intern("tagging"), 1, 1, Qtrue);
1770-
rb_undef_method(cASN1Primitive, "indefinite_length=");
1771-
rb_undef_method(cASN1Primitive, "infinite_length=");
1772-
rb_define_method(cASN1Primitive, "initialize", ossl_asn1_initialize, -1);
17731593
rb_define_method(cASN1Primitive, "to_der", ossl_asn1prim_to_der, 0);
17741594

17751595
/* Document-class: OpenSSL::ASN1::Constructive
@@ -1800,17 +1620,7 @@ Init_ossl_asn1(void)
18001620
* set = OpenSSL::ASN1::Set.new( [ int, str ] )
18011621
*/
18021622
cASN1Constructive = rb_define_class_under(mASN1,"Constructive", cASN1Data);
1803-
rb_include_module(cASN1Constructive, rb_mEnumerable);
1804-
/*
1805-
* May be used as a hint for encoding a value either implicitly or
1806-
* explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
1807-
* _tagging_ is not set when a ASN.1 structure is parsed using
1808-
* OpenSSL::ASN1.decode.
1809-
*/
1810-
rb_attr(cASN1Constructive, rb_intern("tagging"), 1, 1, Qtrue);
1811-
rb_define_method(cASN1Constructive, "initialize", ossl_asn1_initialize, -1);
18121623
rb_define_method(cASN1Constructive, "to_der", ossl_asn1cons_to_der, 0);
1813-
rb_define_method(cASN1Constructive, "each", ossl_asn1cons_each, 0);
18141624

18151625
#define OSSL_ASN1_DEFINE_CLASS(name, super) \
18161626
do{\
@@ -1859,13 +1669,10 @@ do{\
18591669
rb_define_alias(cASN1ObjectId, "short_name", "sn");
18601670
rb_define_alias(cASN1ObjectId, "long_name", "ln");
18611671
rb_define_method(cASN1ObjectId, "==", ossl_asn1obj_eq, 1);
1862-
rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0);
18631672

1864-
rb_define_method(cASN1EndOfContent, "initialize", ossl_asn1eoc_initialize, 0);
18651673
rb_define_method(cASN1EndOfContent, "to_der", ossl_asn1eoc_to_der, 0);
18661674

18671675
class_tag_map = rb_hash_new();
1868-
rb_gc_register_mark_object(class_tag_map);
18691676
rb_hash_aset(class_tag_map, cASN1EndOfContent, INT2NUM(V_ASN1_EOC));
18701677
rb_hash_aset(class_tag_map, cASN1Boolean, INT2NUM(V_ASN1_BOOLEAN));
18711678
rb_hash_aset(class_tag_map, cASN1Integer, INT2NUM(V_ASN1_INTEGER));
@@ -1889,6 +1696,5 @@ do{\
18891696
rb_hash_aset(class_tag_map, cASN1GeneralString, INT2NUM(V_ASN1_GENERALSTRING));
18901697
rb_hash_aset(class_tag_map, cASN1UniversalString, INT2NUM(V_ASN1_UNIVERSALSTRING));
18911698
rb_hash_aset(class_tag_map, cASN1BMPString, INT2NUM(V_ASN1_BMPSTRING));
1892-
1893-
id_each = rb_intern_const("each");
1699+
rb_define_const(mASN1, "CLASS_TAG_MAP", class_tag_map);
18941700
}

ext/openssl/ossl_asn1.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ extern VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
5555
extern VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
5656
extern VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
5757

58+
extern VALUE cASN1EndOfContent; /* END OF CONTENT */
59+
5860
ASN1_TYPE *ossl_asn1_get_asn1type(VALUE);
5961

6062
void Init_ossl_asn1(void);

lib/openssl.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
require 'openssl.so'
1414

1515
require_relative 'openssl/bn'
16+
require_relative 'openssl/asn1'
1617
require_relative 'openssl/pkey'
1718
require_relative 'openssl/cipher'
1819
require_relative 'openssl/digest'

0 commit comments

Comments
 (0)