diff --git a/lib/asn1/check-timegm.c b/lib/asn1/check-timegm.c index 449ef5256..13d3abcf1 100644 --- a/lib/asn1/check-timegm.c +++ b/lib/asn1/check-timegm.c @@ -58,6 +58,15 @@ test_timegm(void) if (t != -1) ret += 1; + _der_gmtime(1159696980, &tm); + if (tm.tm_year != 106 || + tm.tm_mon != 9 || + tm.tm_mday != 1 || + tm.tm_hour != 10 || + tm.tm_min != 3 || + tm.tm_sec != 0) + errx(1, "tmtime failes"); + return ret; } diff --git a/lib/asn1/der_locl.h b/lib/asn1/der_locl.h index 0f65c50a2..a086e18fa 100644 --- a/lib/asn1/der_locl.h +++ b/lib/asn1/der_locl.h @@ -56,6 +56,7 @@ #include "asn1-template.h" time_t _der_timegm (struct tm *); +struct tm * _der_gmtime(time_t t, struct tm *); size_t _heim_len_unsigned (unsigned); size_t _heim_len_int (int); diff --git a/lib/asn1/der_put.c b/lib/asn1/der_put.c index c8192f25f..b8101458a 100644 --- a/lib/asn1/der_put.c +++ b/lib/asn1/der_put.c @@ -426,22 +426,22 @@ der_put_length_and_tag (unsigned char *p, size_t len, size_t len_val, int _heim_time2generalizedtime (time_t t, heim_octet_string *s, int gtimep) { - struct tm *tm; + struct tm tm; const size_t len = gtimep ? 15 : 13; s->data = malloc(len + 1); if (s->data == NULL) return ENOMEM; s->length = len; - tm = gmtime (&t); + _der_gmtime(t, &tm); if (gtimep) snprintf (s->data, len + 1, "%04d%02d%02d%02d%02d%02dZ", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); else snprintf (s->data, len + 1, "%02d%02d%02d%02d%02d%02dZ", - tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); return 0; } diff --git a/lib/asn1/libasn1-exports.def b/lib/asn1/libasn1-exports.def index 3815917dc..6dfb93ea0 100644 --- a/lib/asn1/libasn1-exports.def +++ b/lib/asn1/libasn1-exports.def @@ -8,6 +8,7 @@ EXPORTS SAMFlags2int TicketFlags2int _der_timegm + _der_gmtime _heim_der_set_sort _heim_fix_dce _heim_len_int diff --git a/lib/asn1/timegm.c b/lib/asn1/timegm.c index c72968dc0..b56947841 100644 --- a/lib/asn1/timegm.c +++ b/lib/asn1/timegm.c @@ -42,6 +42,10 @@ is_leap(unsigned y) return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0); } +static const unsigned ndays[2][12] ={ + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; + /* * This is a simplifed version of timegm(3) that doesn't accept out of * bound values that timegm(3) normally accepts but those are not @@ -51,9 +55,6 @@ is_leap(unsigned y) time_t _der_timegm (struct tm *tm) { - static const unsigned ndays[2][12] ={ - {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, - {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; time_t res = 0; unsigned i; @@ -84,3 +85,37 @@ _der_timegm (struct tm *tm) res += tm->tm_sec; return res; } + +struct tm * +_der_gmtime(time_t t, struct tm *tm) +{ + time_t secday = t % (3600 * 24); + time_t days = t / (3600 * 24); + + memset(tm, 0, sizeof(*tm)); + + tm->tm_sec = secday % 60; + tm->tm_min = (secday % 3600) / 60; + tm->tm_hour = secday / 3600; + + tm->tm_year = 70; + while(1) { + unsigned dayinyear = (is_leap(tm->tm_year) ? 366 : 365); + if (days < dayinyear) + break; + tm->tm_year += 1; + days -= dayinyear; + } + tm->tm_mon = 0; + + while (1) { + unsigned daysinmonth = ndays[is_leap(tm->tm_year)][tm->tm_mon]; + if (days < daysinmonth) + break; + days -= daysinmonth; + tm->tm_mon++; + } + tm->tm_mday = days + 1; + + return tm; +}