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

OpenSSL::ASN1.decode supports fractional times & time zones #757

Closed
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
2 changes: 2 additions & 0 deletions ext/openssl/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ def find_openssl_library
x509_h = "openssl/x509.h".freeze
ts_h = "openssl/ts.h".freeze
ssl_h = "openssl/ssl.h".freeze
asn1_h = "openssl/asn1.h".freeze

# compile options
have_func("RAND_egd()", "openssl/rand.h")
Expand Down Expand Up @@ -192,6 +193,7 @@ def find_openssl_library
have_func("EVP_PKEY_check(NULL)", evp_h)
have_func("EVP_PKEY_new_raw_private_key(0, NULL, (unsigned char *)\"\", 0)", evp_h)
have_func("SSL_CTX_set_ciphersuites(NULL, \"\")", ssl_h)
have_func("ASN1_TIME_to_tm(NULL, NULL)", asn1_h)

# added in 3.0.0
have_func("SSL_set0_tmp_dh_pkey(NULL, NULL)", ssl_h)
Expand Down
47 changes: 45 additions & 2 deletions ext/openssl/ossl_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,51 @@ VALUE
asn1time_to_time(const ASN1_TIME *time)
{
struct tm tm;
VALUE argv[6];
VALUE argv[7];
int count;
int usec = 0;

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

#ifdef HAVE_ASN1_TIME_TO_TM
(void)count;
if (!ASN1_TIME_to_tm(time, &tm)) {
ossl_raise(eASN1Error, "ASN1_TIME_to_tm");
}

tm.tm_year += 1900;
tm.tm_mon += 1;

if (time->length > 15 && time->data[14] == '.') {
const unsigned char *f = &time->data[14];
unsigned long f_len = 1;
while (14 + f_len < time->length && ISDIGIT(f[f_len]))
++f_len;
if (f_len > 1) {
char buf[10];
if (f_len > sizeof(buf) - 1)
f_len = sizeof(buf) - 1;
memcpy(buf, f + 1, f_len - 1);
buf[f_len - 1] = '\0';

usec = atoi(buf);
// adjust based on the number of digits
if (f_len < 2) {
usec *= 1000000;
} else if (f_len < 3) {
usec *= 100000;
} else if (f_len < 4) {
usec *= 10000;
} else if (f_len < 5) {
usec *= 1000;
} else if (f_len < 6) {
usec *= 100;
} else if (f_len < 7) {
usec *= 10;
}
}
}
#else
switch (time->type) {
case V_ASN1_UTCTIME:
count = sscanf((const char *)time->data, "%2d%2d%2d%2d%2d%2dZ",
Expand Down Expand Up @@ -59,14 +99,17 @@ asn1time_to_time(const ASN1_TIME *time)
rb_warning("unknown time format");
return Qnil;
}
#endif

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);
argv[6] = INT2NUM(usec);

return rb_funcall2(rb_cTime, rb_intern("utc"), 6, argv);
return rb_funcall2(rb_cTime, rb_intern("utc"), 7, argv);
}

static VALUE
Expand Down
63 changes: 34 additions & 29 deletions test/openssl/test_asn1.rb
Original file line number Diff line number Diff line change
Expand Up @@ -399,49 +399,54 @@ def test_set
def test_utctime
encode_decode_test B(%w{ 17 0D }) + "160908234339Z".b,
OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 9, 8, 23, 43, 39))

if openssl?(1, 1, 1)
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)
}
end

begin
# possible range of UTCTime is 1969-2068 currently
encode_decode_test B(%w{ 17 0D }) + "690908234339Z".b,
OpenSSL::ASN1::UTCTime.new(Time.utc(1969, 9, 8, 23, 43, 39))
rescue OpenSSL::ASN1::ASN1Error
pend "No negative time_t support?"
end
# not implemented
# 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)
# }
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
# 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"))
# decode_test B(%w{ 18 0D }) + "2016120819.5Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0))
# decode_test B(%w{ 18 0D }) + "2016120819,5Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0))
# 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)
# }

if openssl?(1, 1, 1)
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 0F }) + "201612081934-09".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:00"))
# decode_test B(%w{ 18 0D }) + "2016120819.5Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0))
# decode_test B(%w{ 18 0D }) + "2016120819,5Z".b,
# OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0))
# 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)
}
end
end

def test_basic_asn1data
Expand Down
Loading