summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2019-10-23 07:36:30 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2019-10-23 07:36:30 +0000
commit8f7be4cc8f9bbae6fba6023187adaf363c330576 (patch)
tree9e2ba5d310ca4359f0c5ae99efd52e6fb8f50d3a /usr.sbin
parent97a18cf7fd9a87a9a5b7a73b20db79a4b0ab0d64 (diff)
Rewrite the time validity check for mfts. Using ASN1_GENERALIZEDTIME_print
and strptime to convert the timestamp does not correctly account for the timezone. Instead use X509_cmp_time which later on should be replaced with ASN1_time_tm_cmp since the ASN1_STRING_cmp() check at the end will fail around 2049. Problem with timezone reported by Alexandre Hamada (hamada at registro.br). He also tested this diff. OK tb@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/rpki-client/mft.c103
1 files changed, 48 insertions, 55 deletions
diff --git a/usr.sbin/rpki-client/mft.c b/usr.sbin/rpki-client/mft.c
index 848502a9cb0..11cc3546393 100644
--- a/usr.sbin/rpki-client/mft.c
+++ b/usr.sbin/rpki-client/mft.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mft.c,v 1.7 2019/08/13 13:27:26 claudio Exp $ */
+/* $OpenBSD: mft.c,v 1.8 2019/10/23 07:36:29 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -35,49 +35,58 @@ 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;
+}
- 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);
+/*
+ * Validate and verify the time validity of the mft.
+ * Returns 1 if all is good, 0 if mft is stale, any other case -1.
+ * XXX should use ASN1_time_tm_cmp() once libressl is used.
+ */
+static time_t
+check_validity(const ASN1_GENERALIZEDTIME *from,
+ const ASN1_GENERALIZEDTIME *until, const char *fn, int force)
+{
+ time_t now = time(NULL);
+
+ 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,9 +238,8 @@ mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p, int forc
{
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];
if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
cryptowarnx("%s: RFC 6486 section 4.2: Manifest: "
@@ -289,7 +297,7 @@ mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p, int forc
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 +306,11 @@ mft_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p, int forc
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);
- goto out;
- } else if (now < this) {
- warnx("%s: before date interval (clock drift?)", p->fn);
+ rc = check_validity(from, until, p->fn, force);
+ if (rc != 1)
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. */