Index: extern.h =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v retrieving revision 1.64 diff -u -p -r1.64 extern.h --- extern.h 6 May 2021 17:03:57 -0000 1.64 +++ extern.h 8 Jul 2021 17:49:24 -0000 @@ -160,6 +160,10 @@ struct mft { char *aia; /* AIA */ char *aki; /* AKI */ char *ski; /* SKI */ + time_t from; /* eContent thisUpdate */ + time_t until ; /* eContent nextUpdate */ + time_t notbefore; /* EE Cert notBefore */ + time_t notafter; /* EE Cert notAfter */ }; /* Index: mft.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v retrieving revision 1.35 diff -u -p -r1.35 mft.c --- mft.c 14 Jun 2021 12:08:50 -0000 1.35 +++ mft.c 8 Jul 2021 17:49:24 -0000 @@ -261,6 +261,8 @@ mft_parse_econtent(const unsigned char * const ASN1_GENERALIZEDTIME *from, *until; BIGNUM *mft_seqnum = NULL; int i = 0, rc = -1; + struct tm from_tm, until_tm; + char tbuf1[26], tbuf2[26], tbuf3[26], tbuf4[26]; if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) { cryptowarnx("%s: RFC 6486 section 4.2: Manifest: " @@ -338,6 +340,26 @@ mft_parse_econtent(const unsigned char * } from = t->value.generalizedtime; + /* store eContent thisUpdate so we can compare it to EE NotBefore */ + memset(&from_tm, 0, sizeof(from_tm)); + if (generalizedtime_to_tm(from, &from_tm) == 0) { + warnx("%s: embedded from time format invalid", p->fn); + goto out; + } + if ((p->res->from = mktime(&from_tm)) == -1) { + err(1, "mktime failed"); + goto out; + } + + if (difftime(p->res->notbefore, p->res->from) != 0) { + ctime_r(&p->res->from, tbuf1); // mft + ctime_r(&p->res->notbefore, tbuf2); // ee cert + warnx("%s: draft-ietf-sidrops-6486bis-05: unequal thisUpdate " + "notBefore\neContent : %sCertificate: %s", p->fn, tbuf1, + tbuf2); + goto out; + } + t = sk_ASN1_TYPE_value(seq, i++); if (t->type != V_ASN1_GENERALIZEDTIME) { warnx("%s: RFC 6486 section 4.2.1: nextUpdate: " @@ -347,6 +369,26 @@ mft_parse_econtent(const unsigned char * } until = t->value.generalizedtime; + /* store eContent nextUpdate so we can compare it to EE NotAfter */ + memset(&until_tm, 0, sizeof(until_tm)); + if (generalizedtime_to_tm(until, &until_tm) == 0) { + warnx("%s: embedded from time format invalid", p->fn); + goto out; + } + if ((p->res->until = mktime(&until_tm)) == -1) { + err(1, "mktime failed"); + goto out; + } + + if (difftime(p->res->notafter, p->res->until) != 0) { + ctime_r(&p->res->until, tbuf3); // mft + ctime_r(&p->res->notafter, tbuf4); // ee cert + warnx("%s: draft-ietf-sidrops-6486bis-05: unequal nextUpdate " + "notAfter\neContent : %sCertificate: %s", p->fn, tbuf3, + tbuf4); + goto out; + } + rc = check_validity(from, until, p->fn); if (rc != 1) goto out; @@ -402,6 +444,9 @@ mft_parse(X509 **x509, const char *fn) int c, rc = 0; size_t i, cmsz; unsigned char *cms; + const ASN1_TIME *at_na, *at_nb; + struct tm notbefore_tm, notafter_tm; + time_t notbefore, notafter; memset(&p, 0, sizeof(struct parse)); p.fn = fn; @@ -425,6 +470,42 @@ mft_parse(X509 **x509, const char *fn) "missing AIA, AKI or SKI X509 extension", fn); goto out; } + + /* collect EE notBefore so it can be compared to eContent thisUpdate */ + at_nb = X509_get0_notBefore(*x509); + if (at_nb == NULL) { + warnx("%s: X509_get0_notBefore failed", fn); + goto out; + } + memset(¬before_tm, 0, sizeof(notbefore_tm)); + if (ASN1_time_parse(at_nb->data, at_nb->length, ¬before_tm, + 0) == -1) { + warnx("%s: ASN1_time_parse failed", fn); + goto out; + } + if ((notbefore = mktime(¬before_tm)) == -1) { + err(1, "mktime failed"); + goto out; + } + p.res->notbefore = notbefore; + + /* collect EE notAfter so it can be compared to eContent nextUpdate */ + at_na = X509_get0_notAfter(*x509); + if (at_na == NULL) { + warnx("%s: X509_get0_notAfter failed", fn); + goto out; + } + memset(¬after_tm, 0, sizeof(notafter_tm)); + if (ASN1_time_parse(at_na->data, at_na->length, ¬after_tm, + 0) == -1) { + warnx("%s: ASN1_time_parse failed", fn); + goto out; + } + if ((notafter = mktime(¬after_tm)) == -1) { + err(1, "mktime failed"); + goto out; + } + p.res->notafter = notafter; /* * If we're stale, then remove all of the files that the MFT