From: Alberto Leiva Popper Date: Mon, 2 Oct 2023 16:20:27 +0000 (-0600) Subject: Remove timegm() and tm_gmtoff X-Git-Tag: 1.6.0~59 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8c0caefc38587fe66edc89128cfb6958870a7c84;p=thirdparty%2FFORT-validator.git Remove timegm() and tm_gmtoff Perfects portability. Still missing some testing. I hope this is not too aggressive. If there are RPKI objects not using Zulu, this is going to need further tweaking. --- diff --git a/src/asn1/asn1c/GeneralizedTime.c b/src/asn1/asn1c/GeneralizedTime.c index 69b7a098..badade4a 100644 --- a/src/asn1/asn1c/GeneralizedTime.c +++ b/src/asn1/asn1c/GeneralizedTime.c @@ -6,7 +6,6 @@ #define _REENTRANT /* for Sun */ #define __EXTENSIONS__ /* for Sun */ -#define _DEFAULT_SOURCE 1 /* timegm() */ #define _XOPEN_SOURCE 600 /* snprintf(), timezone */ #define _POSIX_C_SOURCE 200112L /* gmtime_r(), localtime_r(), tzset() */ @@ -16,39 +15,6 @@ #include #include -#if defined(sun) || defined(__sun) || defined(__solaris__) -#define _EMULATE_TIMEGM -#endif - -/* - * Where to look for offset from GMT, Phase I. - * Several platforms are known. - */ -#if defined(__FreeBSD__) || defined(__OpenBSD__) \ - || (defined(__GNUC__) && defined(__APPLE_CC__)) \ - || (defined __GLIBC__ && __GLIBC__ >= 2) -#undef HAVE_TM_GMTOFF -#define HAVE_TM_GMTOFF -#endif /* BSDs and newer glibc */ - -/* - * Where to look for offset from GMT, Phase II. - */ -#ifdef HAVE_TM_GMTOFF -#define GMTOFF(tm) ((tm).tm_gmtoff) -#else /* HAVE_TM_GMTOFF */ -#define GMTOFF(tm) (-timezone) -#endif /* HAVE_TM_GMTOFF */ - -#if (defined(_EMULATE_TIMEGM) || !defined(HAVE_TM_GMTOFF)) -#warning "PLEASE STOP AND READ!" -#warning " timegm() is implemented via getenv(\"TZ\")/setenv(\"TZ\"), which may be not thread-safe." -#warning " " -#warning " You must fix the code by inserting appropriate locking" -#warning " if you want to use asn_GT2time() or asn_UT2time()." -#warning "PLEASE STOP AND READ!" -#endif /* _EMULATE_TIMEGM */ - #define ATZVARS do { \ char tzoldbuf[64]; \ char *tzold @@ -79,20 +45,6 @@ tzset(); \ } while(0); } while(0); -#ifndef HAVE_TIMEGM -#ifdef _EMULATE_TIMEGM -static time_t timegm(struct tm *tm) { - time_t tloc; - ATZVARS; - ATZSAVETZ; - tloc = mktime(tm); - ATZOLDTZ; - return tloc; -} -#endif /* _EMULATE_TIMEGM */ -#endif - - #ifndef ASN___INTERNAL_TEST_MODE /* @@ -158,11 +110,12 @@ GeneralizedTime_constraint(const asn_TYPE_descriptor_t *td, const void *sptr, asn_app_constraint_failed_f *ctfailcb, void *app_key) { const GeneralizedTime_t *st = (const GeneralizedTime_t *)sptr; - time_t tloc; - errno = EPERM; /* Just an unlikely error code */ - tloc = asn_GT2time(st, 0, 0); - if(tloc == -1 && errno != EPERM) { + /* asn_GT2time() no longer supports NULL tm and no GMT */ + fprintf(stderr, "GeneralizedTime_constraint() is not implemented for now.\n"); + abort(); + + if(asn_GT2time(st, 0) != 0) { ASN__CTFAIL(app_key, td, sptr, "%s: Invalid time format: %s (%s:%d)", td->name, strerror(errno), __FILE__, __LINE__); @@ -180,20 +133,16 @@ GeneralizedTime_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, asn_enc_rval_t erval; int fv, fd; /* seconds fraction value and number of digits */ struct tm tm; - time_t tloc; /* * Encode as a canonical DER. */ - errno = EPERM; - tloc = asn_GT2time_frac((const GeneralizedTime_t *)sptr, &fv, &fd, &tm, - 1); /* Recognize time */ - if(tloc == -1 && errno != EPERM) { + if(asn_GT2time_frac((const GeneralizedTime_t *)sptr, &fv, &fd, &tm) != 0) { /* Failed to recognize time. Fail completely. */ ASN__ENCODE_FAILED; } - st = asn_time2GT_frac(0, &tm, fv, fd, 1); /* Save time canonically */ + st = asn_time2GT_frac(0, &tm, fv, fd); /* Save time */ if(!st) ASN__ENCODE_FAILED; /* Memory allocation failure. */ erval = OCTET_STRING_encode_der(td, st, tag_mode, tag, cb, app_key); @@ -215,13 +164,11 @@ GeneralizedTime_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int fv, fd; /* fractional parts */ struct tm tm; - errno = EPERM; if(asn_GT2time_frac((const GeneralizedTime_t *)sptr, - &fv, &fd, &tm, 1) == -1 - && errno != EPERM) + &fv, &fd, &tm) != 0) ASN__ENCODE_FAILED; - gt = asn_time2GT_frac(0, &tm, fv, fd, 1); + gt = asn_time2GT_frac(0, &tm, fv, fd); if(!gt) ASN__ENCODE_FAILED; rv = OCTET_STRING_encode_xer_utf8(td, sptr, ilevel, flags, @@ -249,8 +196,7 @@ GeneralizedTime_print(const asn_TYPE_descriptor_t *td, const void *sptr, struct tm tm; int ret; - errno = EPERM; - if(asn_GT2time(st, &tm, 1) == -1 && errno != EPERM) + if(asn_GT2time(st, &tm) != 0) return (cb("", 11, app_key) < 0) ? -1 : 0; ret = snprintf(buf, sizeof(buf), @@ -264,20 +210,20 @@ GeneralizedTime_print(const asn_TYPE_descriptor_t *td, const void *sptr, } } -time_t -asn_GT2time(const GeneralizedTime_t *st, struct tm *ret_tm, int as_gmt) { - return asn_GT2time_frac(st, 0, 0, ret_tm, as_gmt); +int +asn_GT2time(const GeneralizedTime_t *st, struct tm *ret_tm) { + return asn_GT2time_frac(st, 0, 0, ret_tm); } time_t -asn_GT2time_prec(const GeneralizedTime_t *st, int *frac_value, int frac_digits, struct tm *ret_tm, int as_gmt) { +asn_GT2time_prec(const GeneralizedTime_t *st, int *frac_value, int frac_digits, struct tm *ret_tm) { time_t tloc; int fv, fd = 0; if(frac_value) - tloc = asn_GT2time_frac(st, &fv, &fd, ret_tm, as_gmt); + tloc = asn_GT2time_frac(st, &fv, &fd, ret_tm); else - return asn_GT2time_frac(st, 0, 0, ret_tm, as_gmt); + return asn_GT2time_frac(st, 0, 0, ret_tm); if(fd == 0 || frac_digits <= 0) { *frac_value = 0; } else { @@ -300,31 +246,46 @@ asn_GT2time_prec(const GeneralizedTime_t *st, int *frac_value, int frac_digits, return tloc; } -time_t -asn_GT2time_frac(const GeneralizedTime_t *st, int *frac_value, int *frac_digits, struct tm *ret_tm, int as_gmt) { +/* + * I had to tighten this up because timegm() is not standard. + * This outright means time_t is out of reach, which is a nightmare. + * + * rfc6486#section-4.2.1: + * + * The manifestNumber, thisUpdate, and nextUpdate fields are modeled + * after the corresponding fields in X.509 CRLs (see [RFC5280]). + * + * rfc5280#section-4.1.2.5.2: + * + * GeneralizedTime values MUST be + * expressed in Greenwich Mean Time (Zulu) and MUST include seconds + * (i.e., times are YYYYMMDDHHMMSSZ) + * + * This requirement makes the problem more pallatable, because it means we can + * convert the Generalized Time to a simple CST struct tm, and use that instead + * of time_t. + * + * I left fractional seconds in place for now. + * + * The resulting tm is always in CST. + */ +int +asn_GT2time_frac(const GeneralizedTime_t *st, int *frac_value, int *frac_digits, + struct tm *ret_tm) { struct tm tm_s; uint8_t *buf; uint8_t *end; - int gmtoff_h = 0; - int gmtoff_m = 0; - int gmtoff = 0; /* h + m */ - int offset_specified = 0; int fvalue = 0; int fdigits = 0; - time_t tloc; - if(!st || !st->buf) { - errno = EINVAL; - return -1; - } else { - buf = st->buf; - end = buf + st->size; - } + if(!st || !st->buf) + goto garbage; - if(st->size < 10) { - errno = EINVAL; - return -1; - } + buf = st->buf; + end = buf + st->size; + + if(st->size < 10) + goto garbage; /* * Decode first 10 bytes: "AAAAMMJJhh" @@ -335,8 +296,7 @@ asn_GT2time_frac(const GeneralizedTime_t *st, int *frac_value, int *frac_digits, #define B2F(var) do { \ unsigned ch = *buf; \ if(ch < 0x30 || ch > 0x39) { \ - errno = EINVAL; \ - return -1; \ + goto garbage; \ } else { \ var = var * 10 + (ch - 0x30); \ buf++; \ @@ -355,7 +315,7 @@ asn_GT2time_frac(const GeneralizedTime_t *st, int *frac_value, int *frac_digits, B2T(tm_hour); /* 9: h */ B2T(tm_hour); /* 0: h */ - if(buf == end) goto local_finish; + if(buf == end) goto garbage; /* * Parse [mm[ss[(.|,)ffff]]] @@ -365,19 +325,14 @@ asn_GT2time_frac(const GeneralizedTime_t *st, int *frac_value, int *frac_digits, case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: tm_s.tm_min = (*buf++) - 0x30; - if(buf == end) { errno = EINVAL; return -1; } + if(buf == end) goto garbage; B2T(tm_min); break; - case 0x2B: case 0x2D: /* +, - */ - goto offset; - case 0x5A: /* Z */ - goto utc_finish; - default: - errno = EINVAL; - return -1; + default: /* +, -, Z */ + goto garbage; } - if(buf == end) goto local_finish; + if(buf == end) goto garbage; /* * Parse [mm[ss[(.|,)ffff]]] @@ -387,19 +342,14 @@ asn_GT2time_frac(const GeneralizedTime_t *st, int *frac_value, int *frac_digits, case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: tm_s.tm_sec = (*buf++) - 0x30; - if(buf == end) { errno = EINVAL; return -1; } + if(buf == end) goto garbage; B2T(tm_sec); break; - case 0x2B: case 0x2D: /* +, - */ - goto offset; - case 0x5A: /* Z */ - goto utc_finish; - default: - errno = EINVAL; - return -1; + default: /* +, -, Z */ + goto garbage; } - if(buf == end) goto local_finish; + if(buf == end) goto garbage; /* * Parse [mm[ss[(.|,)ffff]]] @@ -430,121 +380,44 @@ asn_GT2time_frac(const GeneralizedTime_t *st, int *frac_value, int *frac_digits, } } - if(buf == end) goto local_finish; - - switch(*buf) { - case 0x2B: case 0x2D: /* +, - */ - goto offset; - case 0x5A: /* Z */ - goto utc_finish; - default: - errno = EINVAL; - return -1; - } - + if(buf == end) goto garbage; -offset: + if ((*buf) != 0x5A) /* Zulu */ + goto garbage; - if(end - buf < 3) { - errno = EINVAL; - return -1; - } - buf++; - B2F(gmtoff_h); - B2F(gmtoff_h); - if(buf[-3] == 0x2D) /* Negative */ - gmtoff = -1; - else - gmtoff = 1; - - if((end - buf) == 2) { - B2F(gmtoff_m); - B2F(gmtoff_m); - } else if(end != buf) { - errno = EINVAL; - return -1; - } - - gmtoff = gmtoff * (3600 * gmtoff_h + 60 * gmtoff_m); - - /* Fall through */ -utc_finish: - - offset_specified = 1; - - /* Fall through */ -local_finish: - - /* - * Validation. - */ + /* Validation */ if((tm_s.tm_mon > 12 || tm_s.tm_mon < 1) || (tm_s.tm_mday > 31 || tm_s.tm_mday < 1) || (tm_s.tm_hour > 23) || (tm_s.tm_sec > 60) - ) { - errno = EINVAL; - return -1; - } + ) + goto garbage; /* Canonicalize */ tm_s.tm_mon -= 1; /* 0 - 11 */ tm_s.tm_year -= 1900; - tm_s.tm_isdst = -1; - - tm_s.tm_sec -= gmtoff; - - /*** AT THIS POINT tm_s is either GMT or local (unknown) ****/ - - if(offset_specified) { - tloc = timegm(&tm_s); - } else { - /* - * Without an offset (or "Z"), - * we can only guess that it is a local zone. - * Interpret it in this fashion. - */ - tloc = mktime(&tm_s); - } - if(tloc == -1) { - errno = EINVAL; - return -1; - } + tm_s.tm_isdst = 0; - if(ret_tm) { - if(as_gmt) { - if(offset_specified) { - *ret_tm = tm_s; - } else { - if(gmtime_r(&tloc, ret_tm) == 0) { - errno = EINVAL; - return -1; - } - } - } else { - if(localtime_r(&tloc, ret_tm) == 0) { - errno = EINVAL; - return -1; - } - } - } + *ret_tm = tm_s; /* Fractions of seconds */ if(frac_value) *frac_value = fvalue; if(frac_digits) *frac_digits = fdigits; - return tloc; + return 0; + +garbage: + errno = EINVAL; + return -1; } GeneralizedTime_t * -asn_time2GT(GeneralizedTime_t *opt_gt, const struct tm *tm, int force_gmt) { - return asn_time2GT_frac(opt_gt, tm, 0, 0, force_gmt); +asn_time2GT(GeneralizedTime_t *opt_gt, const struct tm *tm) { + return asn_time2GT_frac(opt_gt, tm, 0, 0); } GeneralizedTime_t * -asn_time2GT_frac(GeneralizedTime_t *opt_gt, const struct tm *tm, int frac_value, int frac_digits, int force_gmt) { - struct tm tm_s; - long gmtoff; +asn_time2GT_frac(GeneralizedTime_t *opt_gt, const struct tm *tm, int frac_value, int frac_digits) { const unsigned int buf_size = 4 + 2 + 2 /* yyyymmdd */ + 2 + 2 + 2 /* hhmmss */ @@ -566,20 +439,6 @@ asn_time2GT_frac(GeneralizedTime_t *opt_gt, const struct tm *tm, int frac_value, buf = (char *)MALLOC(buf_size); if(!buf) return 0; - gmtoff = GMTOFF(*tm); - - if(force_gmt && gmtoff) { - tm_s = *tm; - tm_s.tm_sec -= gmtoff; - timegm(&tm_s); /* Fix the time */ - tm = &tm_s; -#ifdef HAVE_TM_GMTOFF - assert(!GMTOFF(tm_s)); /* Will fix itself */ -#else /* !HAVE_TM_GMTOFF */ - gmtoff = 0; -#endif - } - size = snprintf(buf, buf_size, "%04d%02d%02d%02d%02d%02d", tm->tm_year + 1900, tm->tm_mon + 1, @@ -628,22 +487,9 @@ asn_time2GT_frac(GeneralizedTime_t *opt_gt, const struct tm *tm, int frac_value, } } - if(force_gmt) { - *p++ = 0x5a; /* "Z" */ - *p++ = 0; - size++; - } else { - int ret; - gmtoff %= 86400; - ret = snprintf(p, buf_size - size, "%+03ld%02ld", - gmtoff / 3600, labs(gmtoff % 3600) / 60); - if(ret != 5) { - FREEMEM(buf); - errno = EINVAL; - return 0; - } - size += ret; - } + *p++ = 0x5a; /* "Z" */ + *p++ = 0; + size++; if(opt_gt) { if(opt_gt->buf) @@ -699,6 +545,10 @@ GeneralizedTime_compare(const asn_TYPE_descriptor_t *td, const void *aptr, (void)td; + /* asn_GT2time_frac() no longer supports NULL tm and no GMT. */ + fprintf(stderr, "GeneralizedTime_compare() is not implemented for now.\n"); + abort(); + if(a && b) { int afrac_value, afrac_digits; int bfrac_value, bfrac_digits; @@ -706,10 +556,10 @@ GeneralizedTime_compare(const asn_TYPE_descriptor_t *td, const void *aptr, time_t at, bt; errno = EPERM; - at = asn_GT2time_frac(a, &afrac_value, &afrac_digits, 0, 0); + at = asn_GT2time_frac(a, &afrac_value, &afrac_digits, 0); aerr = errno; errno = EPERM; - bt = asn_GT2time_frac(b, &bfrac_value, &bfrac_digits, 0, 0); + bt = asn_GT2time_frac(b, &bfrac_value, &bfrac_digits, 0); berr = errno; if(at == -1 && aerr != EPERM) { diff --git a/src/asn1/asn1c/GeneralizedTime.h b/src/asn1/asn1c/GeneralizedTime.h index 471f2830..be517c41 100644 --- a/src/asn1/asn1c/GeneralizedTime.h +++ b/src/asn1/asn1c/GeneralizedTime.h @@ -35,8 +35,6 @@ asn_random_fill_f GeneralizedTime_random_fill; * Some handy helpers. * ***********************/ -struct tm; /* */ - /* * Convert a GeneralizedTime structure into time_t * and optionally into struct tm. @@ -44,13 +42,12 @@ struct tm; /* */ * instead of default local one. * On error returns -1 and errno set to EINVAL */ -time_t asn_GT2time(const GeneralizedTime_t *, struct tm *_optional_tm4fill, - int as_gmt); +int asn_GT2time(const GeneralizedTime_t *, struct tm *_optional_tm4fill); /* A version of the above function also returning the fractions of seconds */ -time_t asn_GT2time_frac(const GeneralizedTime_t *, +int asn_GT2time_frac(const GeneralizedTime_t *, int *frac_value, int *frac_digits, /* (value / (10 ^ digits)) */ - struct tm *_optional_tm4fill, int as_gmt); + struct tm *_optional_tm4fill); /* * Another version returning fractions with defined precision @@ -59,7 +56,7 @@ time_t asn_GT2time_frac(const GeneralizedTime_t *, */ time_t asn_GT2time_prec(const GeneralizedTime_t *, int *frac_value, int frac_digits, - struct tm *_optional_tm4fill, int as_gmt); + struct tm *_optional_tm4fill); /* * Convert a struct tm into GeneralizedTime. @@ -69,9 +66,9 @@ time_t asn_GT2time_prec(const GeneralizedTime_t *, * On error, this function returns 0 and sets errno. */ GeneralizedTime_t *asn_time2GT(GeneralizedTime_t *_optional_gt, - const struct tm *, int force_gmt); + const struct tm *); GeneralizedTime_t *asn_time2GT_frac(GeneralizedTime_t *_optional_gt, - const struct tm *, int frac_value, int frac_digits, int force_gmt); + const struct tm *, int frac_value, int frac_digits); #ifdef __cplusplus } diff --git a/src/asn1/asn1c/UTCTime.c b/src/asn1/asn1c/UTCTime.c index 1c1d8790..cf8df4f5 100644 --- a/src/asn1/asn1c/UTCTime.c +++ b/src/asn1/asn1c/UTCTime.c @@ -76,11 +76,12 @@ int UTCTime_constraint(const asn_TYPE_descriptor_t *td, const void *sptr, asn_app_constraint_failed_f *ctfailcb, void *app_key) { const UTCTime_t *st = (const UTCTime_t *)sptr; - time_t tloc; - errno = EPERM; /* Just an unlikely error code */ - tloc = asn_UT2time(st, 0, 0); - if(tloc == -1 && errno != EPERM) { + /* asn_UT2time() no longer supports NULL tm and no GMT. */ + fprintf(stderr, "UTCTime_constraint() is not implemented for now.\n"); + abort(); + + if(asn_UT2time(st, 0) != 0) { ASN__CTFAIL(app_key, td, sptr, "%s: Invalid time format: %s (%s:%d)", td->name, strerror(errno), __FILE__, __LINE__); return -1; @@ -100,13 +101,11 @@ UTCTime_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, UTCTime_t *ut; struct tm tm; - errno = EPERM; - if(asn_UT2time((const UTCTime_t *)sptr, &tm, 1) == -1 - && errno != EPERM) + if(asn_UT2time((const UTCTime_t *)sptr, &tm) != 0) ASN__ENCODE_FAILED; /* Fractions are not allowed in UTCTime */ - ut = asn_time2UT(0, &tm, 1); + ut = asn_time2UT(0, &tm); if(!ut) ASN__ENCODE_FAILED; rv = OCTET_STRING_encode_xer_utf8(td, sptr, ilevel, flags, @@ -134,8 +133,7 @@ UTCTime_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, struct tm tm; int ret; - errno = EPERM; - if(asn_UT2time(st, &tm, 1) == -1 && errno != EPERM) + if(asn_UT2time(st, &tm) != 0) return (cb("", 11, app_key) < 0) ? -1 : 0; ret = snprintf(buf, sizeof(buf), @@ -150,7 +148,7 @@ UTCTime_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, } time_t -asn_UT2time(const UTCTime_t *st, struct tm *_tm, int as_gmt) { +asn_UT2time(const UTCTime_t *st, struct tm *_tm) { char buf[24]; /* "AAMMJJhhmmss+hhmm" + cushion */ GeneralizedTime_t gt; @@ -173,14 +171,14 @@ asn_UT2time(const UTCTime_t *st, struct tm *_tm, int as_gmt) { gt.buf[1] = 0x30; } - return asn_GT2time(>, _tm, as_gmt); + return asn_GT2time(>, _tm); } UTCTime_t * -asn_time2UT(UTCTime_t *opt_ut, const struct tm *tm, int force_gmt) { +asn_time2UT(UTCTime_t *opt_ut, const struct tm *tm) { GeneralizedTime_t *gt = (GeneralizedTime_t *)opt_ut; - gt = asn_time2GT(gt, tm, force_gmt); + gt = asn_time2GT(gt, tm); if(gt == 0) return 0; assert(gt->size >= 2); @@ -231,15 +229,19 @@ UTCTime_compare(const asn_TYPE_descriptor_t *td, const void *aptr, (void)td; + /* asn_UT2time() no longer supports NULL tm and no GMT. */ + fprintf(stderr, "UTCTime_compare() is not implemented for now.\n"); + abort(); + if(a && b) { time_t at, bt; int aerr, berr; errno = EPERM; - at = asn_UT2time(a, 0, 0); + at = asn_UT2time(a, 0); aerr = errno; errno = EPERM; - bt = asn_UT2time(b, 0, 0); + bt = asn_UT2time(b, 0); berr = errno; if(at == -1 && aerr != EPERM) { diff --git a/src/asn1/asn1c/UTCTime.h b/src/asn1/asn1c/UTCTime.h index 04ba958b..33318cf8 100644 --- a/src/asn1/asn1c/UTCTime.h +++ b/src/asn1/asn1c/UTCTime.h @@ -38,10 +38,10 @@ asn_random_fill_f UTCTime_random_fill; struct tm; /* */ /* See asn_GT2time() in GeneralizedTime.h */ -time_t asn_UT2time(const UTCTime_t *, struct tm *_optional_tm4fill, int as_gmt); +time_t asn_UT2time(const UTCTime_t *, struct tm *_optional_tm4fill); /* See asn_time2GT() in GeneralizedTime.h */ -UTCTime_t *asn_time2UT(UTCTime_t *__opt_ut, const struct tm *, int force_gmt); +UTCTime_t *asn_time2UT(UTCTime_t *__opt_ut, const struct tm *); #ifdef __cplusplus } diff --git a/src/object/manifest.c b/src/object/manifest.c index 07cb74eb..bf6df56d 100644 --- a/src/object/manifest.c +++ b/src/object/manifest.c @@ -41,6 +41,29 @@ decode_manifest(struct signed_object *sobj, struct Manifest **result) ); } +/* + * Expects both arguments to be normalized and CST. + */ +static int +tm_cmp(struct tm *tm1, struct tm *tm2) +{ +#define TM_CMP(field) \ + if (tm1->field < tm2->field) \ + return -1; \ + if (tm1->field > tm2->field) \ + return 1; \ + + TM_CMP(tm_year); + TM_CMP(tm_mon); + TM_CMP(tm_mday); + TM_CMP(tm_hour); + TM_CMP(tm_min); + TM_CMP(tm_sec); + return 0; + +#undef TM_CMP +} + static int validate_dates(GeneralizedTime_t *this, GeneralizedTime_t *next) { @@ -49,44 +72,46 @@ validate_dates(GeneralizedTime_t *this, GeneralizedTime_t *next) tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, \ tm.tm_hour, tm.tm_min, tm.tm_sec - time_t thisUpdate; - time_t nextUpdate; - time_t now; - struct tm thisUpdate_tm; - struct tm nextUpdate_tm; + time_t now_tt; + struct tm now; + struct tm thisUpdate; + struct tm nextUpdate; int error; - /* - * BTW: We only need the tm variables for error messages, which are - * rarely needed. - * So maybe we could get a small performance boost by postponing the - * calls to localtime_r(). - */ - thisUpdate = asn_GT2time(this, &thisUpdate_tm, false); - nextUpdate = asn_GT2time(next, &nextUpdate_tm, false); + error = asn_GT2time(this, &thisUpdate); + if (error) + return pr_val_err("Manifest's thisUpdate date is unparseable."); + error = asn_GT2time(next, &nextUpdate); + if (error) + return pr_val_err("Manifest's nextUpdate date is unparseable."); - if (difftime(thisUpdate, nextUpdate) > 0) { + if (tm_cmp(&thisUpdate, &nextUpdate) > 0) { return pr_val_err( "Manifest's thisUpdate (" TM_FMT ") > nextUpdate (" TM_FMT ").", - TM_ARGS(thisUpdate_tm), - TM_ARGS(nextUpdate_tm)); + TM_ARGS(thisUpdate), + TM_ARGS(nextUpdate)); } - now = 0; - error = get_current_time(&now); + now_tt = 0; + error = get_current_time(&now_tt); if (error) return error; + if (gmtime_r(&now_tt, &now) == NULL) { + error = errno; + return pr_val_err("gmtime_r(now) error %d: %s", error, + strerror(error)); + } - if (difftime(now, thisUpdate) < 0) { + if (tm_cmp(&now, &thisUpdate) < 0) { return pr_val_err( "Manifest is not valid yet. (thisUpdate: " TM_FMT ")", - TM_ARGS(thisUpdate_tm)); + TM_ARGS(thisUpdate)); } - if (difftime(now, nextUpdate) > 0) { + if (tm_cmp(&now, &nextUpdate) > 0) { return incidence(INID_MFT_STALE, "Manifest is stale. (nextUpdate: " TM_FMT ")", - TM_ARGS(nextUpdate_tm)); + TM_ARGS(nextUpdate)); } return 0;