On Wed, Oct 16, 2019 at 07:26:25AM -0300, Alexandre Hamada wrote:
> Hi Tech,
> I would like to suggest to use UTC functions on all date/time convertions,
> to avoid some clock drift errors.
> 
> Kind regards,
> Alexandre Hamada
> 
> https://patch-diff.githubusercontent.com/raw/kristapsdz/rpki-client/pull/9.patch
> 
> From a463f8cb23375f15b74eff49a06e8934423e3dbf Mon Sep 17 00:00:00 2001
> From: dev-gto <[email protected]>
> Date: Wed, 16 Oct 2019 07:22:46 -0300
> Subject: [PATCH] Avoid local time conversion
> 
> ---
>  mft.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/mft.c b/mft.c
> index f9176b4..738f3ff 100644
> --- a/mft.c
> +++ b/mft.c
> @@ -75,8 +75,8 @@ gentime2time(struct parse *p, const ASN1_GENERALIZEDTIME 
> *tp)
>       memset(&tm, 0, sizeof(struct tm));
>       if (strptime(buf, "%b %d %T %Y %Z", &tm) == NULL)
>               errx(EXIT_FAILURE, "%s: strptime", buf);
> -     if ((t = mktime(&tm)) == -1)
> -             errx(EXIT_FAILURE, "%s: mktime", buf);
> +     if ((t = timegm(&tm)) == -1)
> +             errx(EXIT_FAILURE, "%s: timegm", buf);
>       return t;
>  }
> 

Hi Alexandre,

How about this diff instead. This is inspired by OCSP_check_validity() and
uses ASN1_GENERALIZEDTIME_check() and X509_cmp_time() to do the validity
check. I think this has a way better chance to produce the expected
results. My quick testing seems to indicate that it works but review and
testing is very welcome.

-- 
:wq Claudio

Index: mft.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v
retrieving revision 1.7
diff -u -p -r1.7 mft.c
--- mft.c       13 Aug 2019 13:27:26 -0000      1.7
+++ mft.c       16 Oct 2019 20:39:36 -0000
@@ -35,49 +35,57 @@ struct      parse {
        struct mft      *res; /* result object */
 };
 
-/*
- * Convert from the ASN.1 generalised time to a time_t.
- * Return the time.
- * This is a stupid requirement due to using ASN1_GENERALIZEDTIME
- * instead of the native ASN1_TIME functions for comparing time.
- */
-static time_t
-gentime2time(struct parse *p, const ASN1_GENERALIZEDTIME *tp)
+static const char *
+gentime2str(const ASN1_GENERALIZEDTIME *time)
 {
+       static char     buf[64];
        BIO             *mem;
-       char            *pp;
-       char             buf[64];
-       long             len;
-       struct tm        tm;
-       time_t           t;
 
        if ((mem = BIO_new(BIO_s_mem())) == NULL)
                cryptoerrx("BIO_new");
-       if (!ASN1_GENERALIZEDTIME_print(mem, tp))
+       if (!ASN1_GENERALIZEDTIME_print(mem, time))
                cryptoerrx("ASN1_GENERALIZEDTIME_print");
+       if (BIO_gets(mem, buf, sizeof(buf)) < 0)
+               cryptoerrx("BIO_gets");
 
-       /*
-        * The manpage says nothing about being NUL terminated and
-        * strptime(3) needs a string.
-        * So convert into a static buffer of decent size and NUL
-        * terminate in that way.
-        */
-
-       len = BIO_get_mem_data(mem, &pp);
-       if (len < 0 || (size_t)len > sizeof(buf) - 1)
-               errx(EXIT_FAILURE, "BIO_get_mem_data");
-
-       memcpy(buf, pp, len);
-       buf[len] = '\0';
        BIO_free(mem);
+       return buf;
+}
+
+/*
+ * Validate and verify the time validity of the mft.
+ * Returns 1 if all is good, 0 if mft is stale, any other case -1.
+ */
+static time_t
+check_validity(const ASN1_GENERALIZEDTIME *from,
+    const ASN1_GENERALIZEDTIME *until, const char *fn, int force)
+{
+       time_t now = time(NULL);
 
-       memset(&tm, 0, sizeof(struct tm));
-       if (strptime(buf, "%b %d %T %Y %Z", &tm) == NULL)
-               errx(EXIT_FAILURE, "%s: strptime", buf);
-       if ((t = mktime(&tm)) == -1)
-               errx(EXIT_FAILURE, "%s: mktime", buf);
+       if (!ASN1_GENERALIZEDTIME_check(from) ||
+           !ASN1_GENERALIZEDTIME_check(until)) {
+               warnx("%s: embedded time format invalid", fn);
+               return -1;
+       }
+       /* check that until is not before from */
+       if (ASN1_STRING_cmp(until, from) < 0) {
+               warnx("%s: bad update interval", fn);
+               return -1;
+       }
+       /* check that now is not before from */
+       if (X509_cmp_time(from, &now) > 0) {
+               warnx("%s: mft not yet valid %s", fn, gentime2str(from));
+               return -1;
+       }
+       /* check that now is not after until */
+       if (X509_cmp_time(until, &now) < 0) {
+               warnx("%s: mft expired on %s%s", fn, gentime2str(until),
+                   force ? " (ignoring)" : "");
+               if (!force)
+                       return 0;
+       }
 
-       return t;
+       return 1;
 }
 
 /*
@@ -229,6 +237,7 @@ mft_parse_econtent(const unsigned char *
 {
        ASN1_SEQUENCE_ANY       *seq;
        const ASN1_TYPE         *t;
+       const ASN1_GENERALIZEDTIME *from, *until;
        int                      i, rc = -1;
        time_t                   this, next, now = time(NULL);
        char                     buf[64];
@@ -289,7 +298,7 @@ mft_parse_econtent(const unsigned char *
                    p->fn, ASN1_tag2str(t->type), t->type);
                goto out;
        }
-       this = gentime2time(p, t->value.generalizedtime);
+       from = t->value.generalizedtime;
 
        t = sk_ASN1_TYPE_value(seq, i++);
        if (t->type != V_ASN1_GENERALIZEDTIME) {
@@ -298,26 +307,11 @@ mft_parse_econtent(const unsigned char *
                    p->fn, ASN1_tag2str(t->type), t->type);
                goto out;
        }
-       next = gentime2time(p, t->value.generalizedtime);
+       until = t->value.generalizedtime;
 
-       if (this >= next) {
-               warnx("%s: bad update interval", p->fn);
+       rc = check_validity(from, until, p->fn, force);
+       if (rc != 1)
                goto out;
-       } else if (now < this) {
-               warnx("%s: before date interval (clock drift?)", p->fn);
-               goto out;
-       } else if (now >= next) {
-               ctime_r(&next, buf);
-               buf[strlen(buf) - 1] = '\0';
-               if (!force) {
-                       if (verbose > 0)
-                               warnx("%s: stale: expired %s", p->fn, buf);
-                       rc = 0;
-                       goto out;
-               }
-               if (verbose > 0)
-                       warnx("%s: stale: expired %s (ignoring)", p->fn, buf);
-       }
 
        /* File list algorithm. */
 

Reply via email to