diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index dd3732d0a..bd6fd110a 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -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") @@ -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) diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c index 053334207..815e3772b 100644 --- a/ext/openssl/ossl_asn1.c +++ b/ext/openssl/ossl_asn1.c @@ -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", @@ -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 diff --git a/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb index 7b1722e5d..3acadeaaf 100644 --- a/test/openssl/test_asn1.rb +++ b/test/openssl/test_asn1.rb @@ -399,6 +399,20 @@ 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, @@ -406,17 +420,6 @@ def test_utctime 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 @@ -424,24 +427,26 @@ def test_generalizedtime 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