Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 71 additions & 93 deletions ext/openssl/ossl_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,64 +9,81 @@
*/
#include "ossl.h"

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);
/********/
/*
* ASN1 module
*/
#define ossl_asn1_get_value(o) rb_attr_get((o),sivVALUE)
#define ossl_asn1_get_tag(o) rb_attr_get((o),sivTAG)
#define ossl_asn1_get_tagging(o) rb_attr_get((o),sivTAGGING)
#define ossl_asn1_get_tag_class(o) rb_attr_get((o),sivTAG_CLASS)
#define ossl_asn1_get_indefinite_length(o) rb_attr_get((o),sivINDEFINITE_LENGTH)

#define ossl_asn1_set_value(o,v) rb_ivar_set((o),sivVALUE,(v))
#define ossl_asn1_set_tag(o,v) rb_ivar_set((o),sivTAG,(v))
#define ossl_asn1_set_tagging(o,v) rb_ivar_set((o),sivTAGGING,(v))
#define ossl_asn1_set_tag_class(o,v) rb_ivar_set((o),sivTAG_CLASS,(v))
#define ossl_asn1_set_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v))

VALUE mASN1;
static VALUE eASN1Error;

VALUE cASN1Data;
static VALUE cASN1Primitive;
static VALUE cASN1Constructive;

static VALUE cASN1EndOfContent;
static VALUE cASN1Boolean; /* BOOLEAN */
static VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */
static VALUE cASN1BitString; /* BIT STRING */
static VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */
static VALUE cASN1NumericString, cASN1PrintableString;
static VALUE cASN1T61String, cASN1VideotexString;
static VALUE cASN1IA5String, cASN1GraphicString;
static VALUE cASN1ISO64String, cASN1GeneralString;
static VALUE cASN1UniversalString, cASN1BMPString;
static VALUE cASN1Null; /* NULL */
static VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
static VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
static VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */

static VALUE sym_IMPLICIT, sym_EXPLICIT;
static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE;
static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINDEFINITE_LENGTH, sivUNUSED_BITS;
static ID id_each;

/*
* DATE conversion
*/
static VALUE
time_utc_new(VALUE args)
{
return rb_funcallv(rb_cTime, rb_intern("utc"), 6, (VALUE *)args);
}

static VALUE
time_utc_new_rescue(VALUE args, VALUE exc)
{
rb_raise(eASN1Error, "invalid time");
}

VALUE
asn1time_to_time(const ASN1_TIME *time)
{
struct tm tm;
VALUE argv[6];
int count;

memset(&tm, 0, sizeof(struct tm));

switch (time->type) {
case V_ASN1_UTCTIME:
count = sscanf((const char *)time->data, "%2d%2d%2d%2d%2d%2dZ",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min,
&tm.tm_sec);

if (count == 5) {
tm.tm_sec = 0;
} else if (count != 6) {
ossl_raise(rb_eTypeError, "bad UTCTIME format: \"%s\"",
time->data);
}
if (tm.tm_year < 50) {
tm.tm_year += 2000;
} else {
tm.tm_year += 1900;
}
break;
case V_ASN1_GENERALIZEDTIME:
count = sscanf((const char *)time->data, "%4d%2d%2d%2d%2d%2dZ",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min,
&tm.tm_sec);
if (count == 5) {
tm.tm_sec = 0;
}
else if (count != 6) {
ossl_raise(rb_eTypeError, "bad GENERALIZEDTIME format: \"%s\"",
time->data);
}
break;
default:
rb_warning("unknown time format");
return Qnil;
}
argv[0] = INT2NUM(tm.tm_year);
argv[1] = INT2NUM(tm.tm_mon);
argv[2] = INT2NUM(tm.tm_mday);
argv[3] = INT2NUM(tm.tm_hour);
argv[4] = INT2NUM(tm.tm_min);
argv[5] = INT2NUM(tm.tm_sec);

return rb_funcall2(rb_cTime, rb_intern("utc"), 6, argv);
if (!ASN1_TIME_to_tm(time, &tm))
ossl_raise(eASN1Error, "ASN1_TIME_to_tm");

VALUE args[] = {
INT2NUM(tm.tm_year + 1900),
INT2NUM(tm.tm_mon + 1),
INT2NUM(tm.tm_mday),
INT2NUM(tm.tm_hour),
INT2NUM(tm.tm_min),
INT2NUM(tm.tm_sec),
};
return rb_rescue2(time_utc_new, (VALUE)args, time_utc_new_rescue, Qnil,
rb_eArgError, 0);
}

static VALUE
Expand Down Expand Up @@ -190,49 +207,6 @@ ossl_asn1obj_to_string_long_name(const ASN1_OBJECT *obj)
return ossl_asn1obj_to_string_oid(obj);
}

/********/
/*
* ASN1 module
*/
#define ossl_asn1_get_value(o) rb_attr_get((o),sivVALUE)
#define ossl_asn1_get_tag(o) rb_attr_get((o),sivTAG)
#define ossl_asn1_get_tagging(o) rb_attr_get((o),sivTAGGING)
#define ossl_asn1_get_tag_class(o) rb_attr_get((o),sivTAG_CLASS)
#define ossl_asn1_get_indefinite_length(o) rb_attr_get((o),sivINDEFINITE_LENGTH)

#define ossl_asn1_set_value(o,v) rb_ivar_set((o),sivVALUE,(v))
#define ossl_asn1_set_tag(o,v) rb_ivar_set((o),sivTAG,(v))
#define ossl_asn1_set_tagging(o,v) rb_ivar_set((o),sivTAGGING,(v))
#define ossl_asn1_set_tag_class(o,v) rb_ivar_set((o),sivTAG_CLASS,(v))
#define ossl_asn1_set_indefinite_length(o,v) rb_ivar_set((o),sivINDEFINITE_LENGTH,(v))

VALUE mASN1;
static VALUE eASN1Error;

VALUE cASN1Data;
static VALUE cASN1Primitive;
static VALUE cASN1Constructive;

static VALUE cASN1EndOfContent;
static VALUE cASN1Boolean; /* BOOLEAN */
static VALUE cASN1Integer, cASN1Enumerated; /* INTEGER */
static VALUE cASN1BitString; /* BIT STRING */
static VALUE cASN1OctetString, cASN1UTF8String; /* STRINGs */
static VALUE cASN1NumericString, cASN1PrintableString;
static VALUE cASN1T61String, cASN1VideotexString;
static VALUE cASN1IA5String, cASN1GraphicString;
static VALUE cASN1ISO64String, cASN1GeneralString;
static VALUE cASN1UniversalString, cASN1BMPString;
static VALUE cASN1Null; /* NULL */
static VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
static VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
static VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */

static VALUE sym_IMPLICIT, sym_EXPLICIT;
static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE;
static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINDEFINITE_LENGTH, sivUNUSED_BITS;
static ID id_each;

/*
* Ruby to ASN1 converters
*/
Expand Down Expand Up @@ -777,6 +751,10 @@ ossl_asn1data_to_der(VALUE self)
}
}

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

static VALUE
int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
VALUE tc, long *num_read)
Expand Down
59 changes: 46 additions & 13 deletions test/openssl/test_asn1.rb
Original file line number Diff line number Diff line change
Expand Up @@ -426,42 +426,75 @@ def test_utctime
OpenSSL::ASN1::UTCTime.new(Time.new(2049, 12, 31, 23, 0, 0, "-04:00")).to_der
}

# not implemented
# UTC offset (BER): ASN1_TIME_to_tm() may or may not support it
# decode_test B(%w{ 17 11 }) + "500908234339+0930".b,
# OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 39, "+09:30"))
# decode_test B(%w{ 17 0F }) + "5009082343-0930".b,
# OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 0, "-09:30"))
# assert_raise(OpenSSL::ASN1::ASN1Error) {
# OpenSSL::ASN1.decode(B(%w{ 17 0C }) + "500908234339".b)
# }
# assert_raise(OpenSSL::ASN1::ASN1Error) {
# OpenSSL::ASN1.decode(B(%w{ 17 0D }) + "500908234339Y".b)
# }

# Seconds is omitted (BER)
# decode_test B(%w{ 18 0D }) + "201612081934Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 0))

# Fractional seconds is not allowed in UTCTime
assert_raise(OpenSSL::ASN1::ASN1Error) {
OpenSSL::ASN1.decode(B(%w{ 17 0F }) + "160908234339.5Z".b)
}

# Missing "Z"
assert_raise(OpenSSL::ASN1::ASN1Error) {
OpenSSL::ASN1.decode(B(%w{ 17 0C }) + "500908234339".b)
}
assert_raise(OpenSSL::ASN1::ASN1Error) {
OpenSSL::ASN1.decode(B(%w{ 17 0D }) + "500908234339Y".b)
}
end

def test_generalizedtime
encode_decode_test B(%w{ 18 0F }) + "20161208193429Z".b,
OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 29))
encode_decode_test B(%w{ 18 0F }) + "99990908234339Z".b,
OpenSSL::ASN1::GeneralizedTime.new(Time.utc(9999, 9, 8, 23, 43, 39))
# not implemented

# Fractional seconds (DER). Not supported by ASN1_TIME_to_tm()
# because struct tm cannot store it.
# encode_decode_test B(%w{ 18 11 }) + "20161208193439.5Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 39.5))

# UTC offset (BER): ASN1_TIME_to_tm() may or may not support it
# decode_test B(%w{ 18 13 }) + "20161208193439+0930".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 39, "+09:30"))
# decode_test B(%w{ 18 11 }) + "201612081934-0930".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:30"))
# decode_test B(%w{ 18 11 }) + "201612081934-09".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:00"))

# Minutes and seconds are omitted (BER)
# decode_test B(%w{ 18 0B }) + "2016120819Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 0, 0))
# Fractional hours (BER)
# decode_test B(%w{ 18 0D }) + "2016120819.5Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0))
# Fractional hours with "," as the decimal separator (BER)
# decode_test B(%w{ 18 0D }) + "2016120819,5Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0))

# Seconds is omitted (BER)
# decode_test B(%w{ 18 0D }) + "201612081934Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 0))
# Fractional minutes (BER)
# decode_test B(%w{ 18 0F }) + "201612081934.5Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 30))
# decode_test B(%w{ 18 11 }) + "20161208193439.5Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 39.5))
# assert_raise(OpenSSL::ASN1::ASN1Error) {
# OpenSSL::ASN1.decode(B(%w{ 18 0D }) + "201612081934Y".b)
# }

# Missing "Z"
assert_raise(OpenSSL::ASN1::ASN1Error) {
OpenSSL::ASN1.decode(B(%w{ 18 0F }) + "20161208193429Y".b)
}

# Encoding year out of range
assert_raise(OpenSSL::ASN1::ASN1Error) {
OpenSSL::ASN1::GeneralizedTime.new(Time.utc(10000, 9, 8, 23, 43, 39)).to_der
}
end

def test_basic_asn1data
Expand Down