On Mon, May 03, 2021 at 08:37:52AM -0600, Theo de Raadt wrote:
> Job Snijders <[email protected]> wrote:
> 
> >     AS38971,178.57.71.0/24,24,ripe,2021-05-04T05:39:30Z
> 
> This time format is human readable, but these files are largely part
> of the machinery.  And now they need expensive parsing when used.
> 
> Are you sure this shouldn't be an integer since the epoch?

ack. I consulted with a few people: most appear to think an integer is
easier than a string and that the JSON/CSV files themselves are not
primarily intended for human consumption.

Example:

    $ head -1 /var/db/rpki-client/csv ; sort -R /var/db/rpki-client/csv | head 
-3
    ASN,IP Prefix,Max Length,Trust Anchor,Until
    AS136255,2400:ac40:856::/48,48,apnic,1620200715
    AS11427,24.166.164.0/22,22,arin,1620280800
    AS199524,92.223.119.0/24,24,ripe,1620128123

Kind regards,

Job

Index: usr.sbin/rpki-client/extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.63
diff -u -p -r1.63 extern.h
--- usr.sbin/rpki-client/extern.h       14 Apr 2021 18:05:47 -0000      1.63
+++ usr.sbin/rpki-client/extern.h       3 May 2021 16:30:28 -0000
@@ -188,6 +188,7 @@ struct roa {
        char            *aki; /* AKI */
        char            *ski; /* SKI */
        char            *tal; /* basename of TAL for this cert */
+       time_t           until; /* do not use after */
 };
 
 /*
@@ -210,6 +211,7 @@ struct vrp {
        char            *tal; /* basename of TAL for this cert */
        enum afi        afi;
        unsigned char   maxlength;
+       time_t          until;
 };
 /*
  * Tree of VRP sorted by afi, addr, maxlength and asid
Index: usr.sbin/rpki-client/output-csv.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/output-csv.c,v
retrieving revision 1.9
diff -u -p -r1.9 output-csv.c
--- usr.sbin/rpki-client/output-csv.c   19 Apr 2021 17:04:35 -0000      1.9
+++ usr.sbin/rpki-client/output-csv.c   3 May 2021 16:30:28 -0000
@@ -24,15 +24,16 @@ output_csv(FILE *out, struct vrp_tree *v
 {
        struct vrp      *v;
 
-       if (fprintf(out, "ASN,IP Prefix,Max Length,Trust Anchor\n") < 0)
+       if (fprintf(out, "ASN,IP Prefix,Max Length,Trust Anchor,Until\n") < 0)
                return -1;
 
        RB_FOREACH(v, vrp_tree, vrps) {
                char buf[64];
 
                ip_addr_print(&v->addr, v->afi, buf, sizeof(buf));
-               if (fprintf(out, "AS%u,%s,%u,%s\n", v->asid, buf, v->maxlength,
-                   v->tal) < 0)
+
+               if (fprintf(out, "AS%u,%s,%u,%s,%lld\n", v->asid, buf,
+                   v->maxlength, v->tal, v->until) < 0)
                        return -1;
        }
        return 0;
Index: usr.sbin/rpki-client/output-json.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/output-json.c,v
retrieving revision 1.15
diff -u -p -r1.15 output-json.c
--- usr.sbin/rpki-client/output-json.c  8 Apr 2021 19:49:27 -0000       1.15
+++ usr.sbin/rpki-client/output-json.c  3 May 2021 16:30:28 -0000
@@ -101,8 +101,8 @@ output_json(FILE *out, struct vrp_tree *
                ip_addr_print(&v->addr, v->afi, buf, sizeof(buf));
 
                if (fprintf(out, "\t\t{ \"asn\": \"AS%u\", \"prefix\": \"%s\", "
-                   "\"maxLength\": %u, \"ta\": \"%s\" }",
-                   v->asid, buf, v->maxlength, v->tal) < 0)
+                   "\"maxLength\": %u, \"ta\": \"%s\", \"until\": %lld }",
+                   v->asid, buf, v->maxlength, v->tal, v->until) < 0)
                        return -1;
        }
 
Index: usr.sbin/rpki-client/parser.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.7
diff -u -p -r1.7 parser.c
--- usr.sbin/rpki-client/parser.c       1 Apr 2021 08:29:10 -0000       1.7
+++ usr.sbin/rpki-client/parser.c       3 May 2021 16:30:28 -0000
@@ -52,10 +52,12 @@ proc_parser_roa(struct entity *entp,
 {
        struct roa              *roa;
        X509                    *x509;
-       int                      c;
+       int                      c, i;
        struct auth             *a;
        STACK_OF(X509)          *chain;
        STACK_OF(X509_CRL)      *crls;
+       const ASN1_TIME         *at;
+       struct tm                until;
 
        if ((roa = roa_parse(&x509, entp->file)) == NULL)
                return NULL;
@@ -85,17 +87,46 @@ proc_parser_roa(struct entity *entp,
                return NULL;
        }
        X509_STORE_CTX_cleanup(ctx);
-       sk_X509_free(chain);
-       sk_X509_CRL_free(crls);
-       X509_free(x509);
+
+       /*
+        * Scan the stack of CRLs to figure out the soonest transitive
+        * expiry moment
+        */
+       for (i = 0; i < sk_X509_CRL_num(crls); i++) {
+               X509_CRL *ci = sk_X509_CRL_value(crls, i);
+               if (ci->crl == NULL) {
+                       err(1, "sk_X509_value failed");
+                       goto out;
+               }
+               at = X509_CRL_get0_nextUpdate(ci);
+               if (at == NULL) {
+                       err(1, "X509_CRL_get0_nextUpdate failed");
+                       goto out;
+               }
+               if (ASN1_time_parse(at->data, at->length, &until,
+                   V_ASN1_UTCTIME) != V_ASN1_UTCTIME) {
+                       err(1, "ASN1_time_parse failed");
+                       goto out;
+               }
+               if (mktime(&until) == -1) {
+                       err(1, "mktime failed");
+                       goto out;
+               }
+               if (roa->until > mktime(&until))
+                       roa->until = mktime(&until);
+       }
 
        /*
         * If the ROA isn't valid, we accept it anyway and depend upon
         * the code around roa_read() to check the "valid" field itself.
         */
-
        if (valid_roa(entp->file, auths, roa))
                roa->valid = 1;
+
+out:
+       sk_X509_free(chain);
+       sk_X509_CRL_free(crls);
+       X509_free(x509);
 
        return roa;
 }
Index: usr.sbin/rpki-client/roa.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/roa.c,v
retrieving revision 1.17
diff -u -p -r1.17 roa.c
--- usr.sbin/rpki-client/roa.c  29 Mar 2021 06:50:44 -0000      1.17
+++ usr.sbin/rpki-client/roa.c  3 May 2021 16:30:28 -0000
@@ -335,6 +335,8 @@ roa_parse(X509 **x509, const char *fn)
        size_t           cmsz;
        unsigned char   *cms;
        int              rc = 0;
+       const ASN1_TIME *at;
+       struct tm        until;
 
        memset(&p, 0, sizeof(struct parse));
        p.fn = fn;
@@ -358,6 +360,21 @@ roa_parse(X509 **x509, const char *fn)
                goto out;
        }
 
+       at = X509_get0_notAfter(*x509);
+       if (at == NULL) {
+               warnx("%s: X509_get0_notAfter failed", fn);
+               goto out;
+       }
+       if (ASN1_time_parse(at->data, at->length, &until, 0) == -1) {
+               warnx("%s: ASN1_time_parse failed", fn);
+               goto out;
+       }
+       if (mktime(&until) == -1) {
+               err(1, "mktime failed");
+               goto out;
+       }
+       p.res->until = mktime(&until);
+       
        if (!roa_parse_econtent(cms, cmsz, &p))
                goto out;
 
@@ -404,6 +421,7 @@ roa_buffer(struct ibuf *b, const struct 
        io_simple_buffer(b, &p->valid, sizeof(int));
        io_simple_buffer(b, &p->asid, sizeof(uint32_t));
        io_simple_buffer(b, &p->ipsz, sizeof(size_t));
+       io_simple_buffer(b, &p->until, sizeof(time_t));
 
        for (i = 0; i < p->ipsz; i++) {
                io_simple_buffer(b, &p->ips[i].afi, sizeof(enum afi));
@@ -436,6 +454,7 @@ roa_read(int fd)
        io_simple_read(fd, &p->valid, sizeof(int));
        io_simple_read(fd, &p->asid, sizeof(uint32_t));
        io_simple_read(fd, &p->ipsz, sizeof(size_t));
+       io_simple_read(fd, &p->until, sizeof(time_t));
 
        if ((p->ips = calloc(p->ipsz, sizeof(struct roa_ip))) == NULL)
                err(1, NULL);
@@ -476,6 +495,7 @@ roa_insert_vrps(struct vrp_tree *tree, s
                v->addr = roa->ips[i].addr;
                v->maxlength = roa->ips[i].maxlength;
                v->asid = roa->asid;
+               v->until = roa->until;
                if ((v->tal = strdup(roa->tal)) == NULL)
                        err(1, NULL);
                if (RB_INSERT(vrp_tree, tree, v) == NULL)
@@ -522,6 +542,11 @@ vrpcmp(struct vrp *a, struct vrp *b)
        if (a->asid < b->asid)
                return -1;
 
+       if (a->until > b->until)
+               return 1;
+       if (a->until < b->until)
+               return -1;
+       
        return 0;
 }
 
Index: regress/usr.sbin/rpki-client/Makefile.inc
===================================================================
RCS file: /cvs/src/regress/usr.sbin/rpki-client/Makefile.inc,v
retrieving revision 1.9
diff -u -p -r1.9 Makefile.inc
--- regress/usr.sbin/rpki-client/Makefile.inc   1 Apr 2021 06:47:18 -0000       
1.9
+++ regress/usr.sbin/rpki-client/Makefile.inc   3 May 2021 16:30:28 -0000
@@ -40,14 +40,23 @@ mft_gen.c: mft.c
        cat $> >> [email protected]
        mv -f [email protected] $@
 
-CLEANFILES += mft_gen.c mft_gen.c.tmp
+# Provide missing prototypes for OpenSSL
+roa_gen.c: roa.c
+       echo '#include <openssl/asn1.h>\n' > [email protected]
+       echo 'int ASN1_time_parse(const char *, size_t, struct tm *, int);' \
+               >> [email protected]
+       echo 'int ASN1_time_tm_cmp(struct tm *, struct tm *);' >> [email protected]
+       cat $> >> [email protected]
+       mv -f [email protected] $@
+
+CLEANFILES += mft_gen.c mft_gen.c.tmp roa_gen.c roa_gen.c.tmp
 
 SRCS_test-mft+=        test-mft.c mft_gen.c cms.c x509.c io.c log.c validate.c 
\
                encoding.c dummy.c
 run-regress-test-mft: test-mft
        ./test-mft -v ${.CURDIR}/../mft/*.mft
 
-SRCS_test-roa= test-roa.c roa.c cms.c x509.c ip.c as.c io.c log.c encoding.c
+SRCS_test-roa+=        test-roa.c roa_gen.c cms.c x509.c ip.c as.c io.c log.c 
encoding.c
 run-regress-test-roa: test-roa
        ./test-roa -v ${.CURDIR}/../roa/*.roa
 
Index: regress/usr.sbin/rpki-client/test-roa.c
===================================================================
RCS file: /cvs/src/regress/usr.sbin/rpki-client/test-roa.c,v
retrieving revision 1.10
diff -u -p -r1.10 test-roa.c
--- regress/usr.sbin/rpki-client/test-roa.c     29 Mar 2021 15:47:34 -0000      
1.10
+++ regress/usr.sbin/rpki-client/test-roa.c     3 May 2021 16:30:28 -0000
@@ -32,6 +32,14 @@
 
 #include "test-common.c"
 
+#ifndef ASN1error
+void
+ASN1error(int err)
+{
+       ASN1err(0, err);
+}
+#endif
+
 int verbose;
 
 static void
Index: regress/usr.sbin/rpki-client/openssl11/Makefile
===================================================================
RCS file: /cvs/src/regress/usr.sbin/rpki-client/openssl11/Makefile,v
retrieving revision 1.2
diff -u -p -r1.2 Makefile
--- regress/usr.sbin/rpki-client/openssl11/Makefile     9 Nov 2020 16:05:10 
-0000       1.2
+++ regress/usr.sbin/rpki-client/openssl11/Makefile     3 May 2021 16:30:28 
-0000
@@ -13,6 +13,7 @@ a_time_tm_gen.c: a_time_tm.c
 CLEANFILES += a_time_tm_gen.c a_time_tm_gen.c.tmp
 
 SRCS_test-mft =        a_time_tm_gen.c o_time.c
+SRCS_test-roa =        a_time_tm_gen.c o_time.c
 CFLAGS +=      -I${.CURDIR}/../../../../lib/libcrypto/
 
 .PATH:         ${.CURDIR}/..

Reply via email to