Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rewriting most of the asn1 init code in ruby #740

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
230 changes: 23 additions & 207 deletions ext/openssl/ossl_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset,
int depth, int yield, long *num_read);
static VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self);

/*
* DATE conversion
Expand Down Expand Up @@ -638,35 +637,6 @@ ossl_asn1_class2sym(int tc)
return sym_UNIVERSAL;
}

/*
* call-seq:
* OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data
*
* _value_: Please have a look at Constructive and Primitive to see how Ruby
* types are mapped to ASN.1 types and vice versa.
*
* _tag_: An Integer indicating the tag number.
*
* _tag_class_: A Symbol indicating the tag class. Please cf. ASN1 for
* possible values.
*
* == Example
* asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)
* tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER
*/
static VALUE
ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class)
{
if(!SYMBOL_P(tag_class))
ossl_raise(eASN1Error, "invalid tag class");
ossl_asn1_set_tag(self, tag);
ossl_asn1_set_value(self, value);
ossl_asn1_set_tag_class(self, tag_class);
ossl_asn1_set_indefinite_length(self, Qfalse);

return self;
}

static VALUE
to_der_internal(VALUE self, int constructed, int indef_len, VALUE body)
{
Expand Down Expand Up @@ -795,20 +765,19 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
if (tc == sym_UNIVERSAL &&
tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) {
VALUE klass = *ossl_asn1_info[tag].klass;
VALUE args[4];
args[0] = value;
args[1] = INT2NUM(tag);
args[2] = Qnil;
args[3] = tc;
asn1data = rb_obj_alloc(klass);
ossl_asn1_initialize(4, args, asn1data);
if (tag == V_ASN1_EOC)
asn1data = rb_funcall(cASN1EndOfContent, rb_intern("new"), 0);
else {
VALUE args[4] = { value, INT2NUM(tag), Qnil, tc };
asn1data = rb_funcall3(klass, rb_intern("new"), 4, args);
}
if(tag == V_ASN1_BIT_STRING){
rb_ivar_set(asn1data, sivUNUSED_BITS, LONG2NUM(flag));
}
}
else {
asn1data = rb_obj_alloc(cASN1Data);
ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), tc);
VALUE args[3] = { value, INT2NUM(tag), tc };
asn1data = rb_funcall3(cASN1Data, rb_intern("new"), 3, args);
}

return asn1data;
Expand Down Expand Up @@ -842,20 +811,22 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
}

if (tc == sym_UNIVERSAL) {
VALUE args[4];
if (tag == V_ASN1_SEQUENCE || tag == V_ASN1_SET)
asn1data = rb_obj_alloc(*ossl_asn1_info[tag].klass);
else
asn1data = rb_obj_alloc(cASN1Constructive);
args[0] = ary;
args[1] = INT2NUM(tag);
args[2] = Qnil;
args[3] = tc;
ossl_asn1_initialize(4, args, asn1data);
if (tag == V_ASN1_EOC)
asn1data = rb_funcall(cASN1EndOfContent, rb_intern("new"), 0);
else if (tag == V_ASN1_SEQUENCE) {
VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
asn1data = rb_funcall3(cASN1Sequence, rb_intern("new"), 4, args);
} else if (tag == V_ASN1_SET) {
VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
asn1data = rb_funcall3(cASN1Set, rb_intern("new"), 4, args);
} else {
VALUE args[4] = { ary, INT2NUM(tag), Qnil, tc };
asn1data = rb_funcall3(cASN1Constructive, rb_intern("new"), 4, args);
}
}
else {
asn1data = rb_obj_alloc(cASN1Data);
ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), tc);
VALUE args[3] = {ary, INT2NUM(tag), tc};
asn1data = rb_funcall3(cASN1Data, rb_intern("new"), 3, args);
}

if (indefinite)
Expand Down Expand Up @@ -1048,83 +1019,6 @@ ossl_asn1_decode_all(VALUE self, VALUE obj)
return ary;
}

/*
* call-seq:
* OpenSSL::ASN1::Primitive.new(value [, tag, tagging, tag_class ]) => Primitive
*
* _value_: is mandatory.
*
* _tag_: optional, may be specified for tagged values. If no _tag_ is
* specified, the UNIVERSAL tag corresponding to the Primitive sub-class
* is used by default.
*
* _tagging_: may be used as an encoding hint to encode a value either
* explicitly or implicitly, see ASN1 for possible values.
*
* _tag_class_: if _tag_ and _tagging_ are +nil+ then this is set to
* +:UNIVERSAL+ by default. If either _tag_ or _tagging_ are set then
* +:CONTEXT_SPECIFIC+ is used as the default. For possible values please
* cf. ASN1.
*
* == Example
* int = OpenSSL::ASN1::Integer.new(42)
* zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)
* private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)
*/
static VALUE
ossl_asn1_initialize(int argc, VALUE *argv, VALUE self)
{
VALUE value, tag, tagging, tag_class;
int default_tag;

rb_scan_args(argc, argv, "13", &value, &tag, &tagging, &tag_class);
default_tag = ossl_asn1_default_tag(self);

if (default_tag == -1 || argc > 1) {
if(NIL_P(tag))
ossl_raise(eASN1Error, "must specify tag number");
if(!NIL_P(tagging) && !SYMBOL_P(tagging))
ossl_raise(eASN1Error, "invalid tagging method");
if(NIL_P(tag_class)) {
if (NIL_P(tagging))
tag_class = sym_UNIVERSAL;
else
tag_class = sym_CONTEXT_SPECIFIC;
}
if(!SYMBOL_P(tag_class))
ossl_raise(eASN1Error, "invalid tag class");
}
else{
tag = INT2NUM(default_tag);
tagging = Qnil;
tag_class = sym_UNIVERSAL;
}
ossl_asn1_set_tag(self, tag);
ossl_asn1_set_value(self, value);
ossl_asn1_set_tagging(self, tagging);
ossl_asn1_set_tag_class(self, tag_class);
ossl_asn1_set_indefinite_length(self, Qfalse);
if (default_tag == V_ASN1_BIT_STRING)
rb_ivar_set(self, sivUNUSED_BITS, INT2FIX(0));

return self;
}

static VALUE
ossl_asn1eoc_initialize(VALUE self) {
VALUE tag, tagging, tag_class, value;
tag = INT2FIX(0);
tagging = Qnil;
tag_class = sym_UNIVERSAL;
value = rb_str_new("", 0);
ossl_asn1_set_tag(self, tag);
ossl_asn1_set_value(self, value);
ossl_asn1_set_tagging(self, tagging);
ossl_asn1_set_tag_class(self, tag_class);
ossl_asn1_set_indefinite_length(self, Qfalse);
return self;
}

static VALUE
ossl_asn1eoc_to_der(VALUE self)
{
Expand Down Expand Up @@ -1216,27 +1110,6 @@ ossl_asn1cons_to_der(VALUE self)
return to_der_internal(self, 1, indef_len, str);
}

/*
* call-seq:
* asn1_ary.each { |asn1| block } => asn1_ary
*
* Calls the given block once for each element in self, passing that element
* as parameter _asn1_. If no block is given, an enumerator is returned
* instead.
*
* == Example
* asn1_ary.each do |asn1|
* puts asn1
* end
*/
static VALUE
ossl_asn1cons_each(VALUE self)
{
rb_block_call(ossl_asn1_get_value(self), id_each, 0, 0, 0, 0);

return self;
}

/*
* call-seq:
* OpenSSL::ASN1::ObjectId.register(object_id, short_name, long_name)
Expand Down Expand Up @@ -1657,42 +1530,6 @@ Init_ossl_asn1(void)
* puts int2.value # => 1
*/
cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject);
/*
* Carries the value of a ASN.1 type.
* Please confer Constructive and Primitive for the mappings between
* ASN.1 data types and Ruby classes.
*/
rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0);
/*
* An Integer representing the tag number of this ASN1Data. Never +nil+.
*/
rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0);
/*
* A Symbol representing the tag class of this ASN1Data. Never +nil+.
* See ASN1Data for possible values.
*/
rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0);
/*
* Never +nil+. A boolean value indicating whether the encoding uses
* indefinite length (in the case of parsing) or whether an indefinite
* length form shall be used (in the encoding case).
* In DER, every value uses definite length form. But in scenarios where
* large amounts of data need to be transferred it might be desirable to
* have some kind of streaming support available.
* For example, huge OCTET STRINGs are preferably sent in smaller-sized
* chunks, each at a time.
* This is possible in BER by setting the length bytes of an encoding
* to zero and by this indicating that the following value will be
* sent in chunks. Indefinite length encodings are always constructed.
* The end of such a stream of chunks is indicated by sending a EOC
* (End of Content) tag. SETs and SEQUENCEs may use an indefinite length
* encoding, but also primitive types such as e.g. OCTET STRINGS or
* BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
*/
rb_attr(cASN1Data, rb_intern("indefinite_length"), 1, 1, 0);
rb_define_alias(cASN1Data, "infinite_length", "indefinite_length");
rb_define_alias(cASN1Data, "infinite_length=", "indefinite_length=");
rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3);
rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0);

/* Document-class: OpenSSL::ASN1::Primitive
Expand Down Expand Up @@ -1760,16 +1597,6 @@ Init_ossl_asn1(void)
* prim_zero_tagged_explicit = <class>.new(value, 0, :EXPLICIT)
*/
cASN1Primitive = rb_define_class_under(mASN1, "Primitive", cASN1Data);
/*
* May be used as a hint for encoding a value either implicitly or
* explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
* _tagging_ is not set when a ASN.1 structure is parsed using
* OpenSSL::ASN1.decode.
*/
rb_attr(cASN1Primitive, rb_intern("tagging"), 1, 1, Qtrue);
rb_undef_method(cASN1Primitive, "indefinite_length=");
rb_undef_method(cASN1Primitive, "infinite_length=");
rb_define_method(cASN1Primitive, "initialize", ossl_asn1_initialize, -1);
rb_define_method(cASN1Primitive, "to_der", ossl_asn1prim_to_der, 0);

/* Document-class: OpenSSL::ASN1::Constructive
Expand Down Expand Up @@ -1800,17 +1627,7 @@ Init_ossl_asn1(void)
* set = OpenSSL::ASN1::Set.new( [ int, str ] )
*/
cASN1Constructive = rb_define_class_under(mASN1,"Constructive", cASN1Data);
rb_include_module(cASN1Constructive, rb_mEnumerable);
/*
* May be used as a hint for encoding a value either implicitly or
* explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
* _tagging_ is not set when a ASN.1 structure is parsed using
* OpenSSL::ASN1.decode.
*/
rb_attr(cASN1Constructive, rb_intern("tagging"), 1, 1, Qtrue);
rb_define_method(cASN1Constructive, "initialize", ossl_asn1_initialize, -1);
rb_define_method(cASN1Constructive, "to_der", ossl_asn1cons_to_der, 0);
rb_define_method(cASN1Constructive, "each", ossl_asn1cons_each, 0);

#define OSSL_ASN1_DEFINE_CLASS(name, super) \
do{\
Expand Down Expand Up @@ -1859,9 +1676,7 @@ do{\
rb_define_alias(cASN1ObjectId, "short_name", "sn");
rb_define_alias(cASN1ObjectId, "long_name", "ln");
rb_define_method(cASN1ObjectId, "==", ossl_asn1obj_eq, 1);
rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0);

rb_define_method(cASN1EndOfContent, "initialize", ossl_asn1eoc_initialize, 0);
rb_define_method(cASN1EndOfContent, "to_der", ossl_asn1eoc_to_der, 0);

class_tag_map = rb_hash_new();
Expand Down Expand Up @@ -1889,6 +1704,7 @@ do{\
rb_hash_aset(class_tag_map, cASN1GeneralString, INT2NUM(V_ASN1_GENERALSTRING));
rb_hash_aset(class_tag_map, cASN1UniversalString, INT2NUM(V_ASN1_UNIVERSALSTRING));
rb_hash_aset(class_tag_map, cASN1BMPString, INT2NUM(V_ASN1_BMPSTRING));
rb_define_const(mASN1, "CLASS_TAG_MAP", class_tag_map);

id_each = rb_intern_const("each");
}
2 changes: 2 additions & 0 deletions ext/openssl/ossl_asn1.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ extern VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
extern VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
extern VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */

extern VALUE cASN1EndOfContent; /* END OF CONTENT */

ASN1_TYPE *ossl_asn1_get_asn1type(VALUE);

void Init_ossl_asn1(void);
Expand Down
1 change: 1 addition & 0 deletions lib/openssl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
require 'openssl.so'

require_relative 'openssl/bn'
require_relative 'openssl/asn1'
require_relative 'openssl/pkey'
require_relative 'openssl/cipher'
require_relative 'openssl/digest'
Expand Down