On Mon, Dec 07, 2020 at 09:55:06PM +0000, Job Snijders wrote:
> On Mon, Dec 07, 2020 at 10:03:57PM +0100, Claudio Jeker wrote:
> > So ghostbuster records (rfc6493) are showing up in RPKI datasets and
> > instead of silently ignoring them rpki-client should first of all validate
> > the file hash in the manifest and later on also validate the CMS data.
> > 
> > This first diff does ensure that all files in an mft are present and have
> > a valid hash (no matter if rpki-client is able to handle them or not).
> > While enquing the work for the parser issue a warning for files that are
> > currently not known (anything else than .crl, .cer and .roa).
> > 
> > Seems to work for me :)
> 
> OK job@

Actually here is a diff that does the full verify of .gbr files (or at
least the one that is currently in rpki) 
This diff does currently nothing with the provided VCARD.

-- 
:wq Claudio

Index: Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/Makefile,v
retrieving revision 1.14
diff -u -p -r1.14 Makefile
--- Makefile    4 Dec 2019 12:40:17 -0000       1.14
+++ Makefile    7 Dec 2020 21:39:04 -0000
@@ -1,7 +1,7 @@
 #      $OpenBSD: Makefile,v 1.14 2019/12/04 12:40:17 deraadt Exp $
 
 PROG=  rpki-client
-SRCS=  as.c cert.c cms.c crl.c io.c ip.c log.c main.c mft.c output.c \
+SRCS=  as.c cert.c cms.c crl.c gbr.c io.c ip.c log.c main.c mft.c output.c \
        output-bgpd.c output-bird.c output-csv.c output-json.c \
        roa.c rsync.c tal.c validate.c x509.c
 MAN=   rpki-client.8
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.35
diff -u -p -r1.35 extern.h
--- extern.h    2 Dec 2020 15:31:15 -0000       1.35
+++ extern.h    7 Dec 2020 21:45:36 -0000
@@ -185,6 +185,15 @@ struct roa {
 };
 
 /*
+ * A single Ghostbuster record
+ */
+struct gbr {
+       char            *vcard;
+       char            *ski; /* SKI */
+       char            *aki; /* AKI */
+};
+
+/*
  * A single VRP element (including ASID)
  */
 struct vrp {
@@ -245,7 +254,8 @@ enum rtype {
        RTYPE_MFT,
        RTYPE_ROA,
        RTYPE_CER,
-       RTYPE_CRL
+       RTYPE_CRL,
+       RTYPE_GBR,
 };
 
 /*
@@ -264,6 +274,7 @@ struct      stats {
        size_t   roas_invalid; /* invalid resources */
        size_t   repos; /* repositories */
        size_t   crls; /* revocation lists */
+       size_t   gbrs; /* ghostbuster records */
        size_t   vrps; /* total number of vrps */
        size_t   uniqs; /* number of unique vrps */
        size_t   del_files; /* number of files removed in cleanup */
@@ -302,6 +313,9 @@ struct roa  *roa_parse(X509 **, const cha
 struct roa     *roa_read(int);
 void            roa_insert_vrps(struct vrp_tree *, struct roa *, size_t *,
                    size_t *);
+
+void            gbr_free(struct gbr *);
+struct gbr     *gbr_parse(X509 **, const char *);
 
 /* crl.c */
 X509_CRL       *crl_parse(const char *, const unsigned char *);
Index: gbr.c
===================================================================
RCS file: gbr.c
diff -N gbr.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gbr.c       7 Dec 2020 22:11:26 -0000
@@ -0,0 +1,88 @@
+/*     $OpenBSD$ */
+/*
+ * Copyright (c) 2020 Claudio Jeker <[email protected]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <err.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+/*
+ * Parse results and data of the manifest file.
+ */
+struct parse {
+       const char       *fn; /* manifest file name */
+       struct gbr       *res; /* results */
+};
+
+/*
+ * Parse a full RFC 6493 file and signed by the certificate "cacert"
+ * (the latter is optional and may be passed as NULL to disable).
+ * Returns the payload or NULL if the document was malformed.
+ */
+struct gbr *
+gbr_parse(X509 **x509, const char *fn)
+{
+       struct parse     p;
+       size_t           cmsz;
+       unsigned char   *cms;
+
+       memset(&p, 0, sizeof(struct parse));
+       p.fn = fn;
+
+       /* OID from section 9.1, RFC 6493. */
+
+       cms = cms_parse_validate(x509, fn,
+           "1.2.840.113549.1.9.16.1.35", NULL, &cmsz);
+       if (cms == NULL)
+               return NULL;
+
+       if ((p.res = calloc(1, sizeof(struct roa))) == NULL)
+               err(1, NULL);
+       if ((p.res->vcard = strndup(cms, cmsz)) == NULL)
+               err(1, NULL);
+       if (!x509_get_ski_aki(*x509, fn, &p.res->ski, &p.res->aki)) {
+               gbr_free(p.res);
+               X509_free(*x509);
+               *x509 = NULL;
+               return NULL;
+       }
+
+       free(cms);
+       return p.res;
+}
+
+/*
+ * Free an GBR pointer.
+ * Safe to call with NULL.
+ */
+void
+gbr_free(struct gbr *p)
+{
+
+       if (p == NULL)
+               return;
+       free(p->aki);
+       free(p->ski);
+       free(p->vcard);
+       free(p);
+}
Index: main.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
retrieving revision 1.85
diff -u -p -r1.85 main.c
--- main.c      2 Dec 2020 15:31:15 -0000       1.85
+++ main.c      7 Dec 2020 21:57:17 -0000
@@ -518,6 +518,27 @@ queue_add_from_mft_set(int fd, struct en
                        continue;
                queue_add_from_mft(fd, q, mft->file, f, RTYPE_ROA, eid);
        }
+
+       for (i = 0; i < mft->filesz; i++) {
+               f = &mft->files[i];
+               sz = strlen(f->file);
+               assert(sz > 4);
+               if (strcasecmp(f->file + sz - 4, ".gbr"))
+                       continue;
+               queue_add_from_mft(fd, q, mft->file, f, RTYPE_GBR, eid);
+       }
+
+       for (i = 0; i < mft->filesz; i++) {
+               f = &mft->files[i];
+               sz = strlen(f->file);
+               assert(sz > 4);
+               if (strcasecmp(f->file + sz - 4, ".crl") == 0 ||
+                   strcasecmp(f->file + sz - 4, ".cer") == 0 ||
+                   strcasecmp(f->file + sz - 4, ".roa") == 0 ||
+                   strcasecmp(f->file + sz - 4, ".gbr") == 0)
+                       continue;
+               logx("%s: unsupported file type: %s", mft->file, f->file);
+       }
 }
 
 /*
@@ -937,6 +958,49 @@ proc_parser_crl(struct entity *entp, X50
        }
 }
 
+/*
+ * Parse a ghostbuster record
+ */
+static void
+proc_parser_gbr(struct entity *entp, X509_STORE *store,
+    X509_STORE_CTX *ctx, struct auth_tree *auths, struct crl_tree *crlt)
+{
+       struct gbr              *gbr;
+       X509                    *x509;
+       int                      c;
+       struct auth             *a;
+       STACK_OF(X509)          *chain;
+       STACK_OF(X509_CRL)      *crls;
+
+       if ((gbr = gbr_parse(&x509, entp->uri)) == NULL)
+               return;
+
+       a = valid_ski_aki(entp->uri, auths, gbr->ski, gbr->aki);
+
+       build_chain(a, &chain);
+       build_crls(a, crlt, &crls);
+
+       assert(x509 != NULL);
+       if (!X509_STORE_CTX_init(ctx, store, x509, chain))
+               cryptoerrx("X509_STORE_CTX_init");
+       X509_STORE_CTX_set_flags(ctx,
+           X509_V_FLAG_IGNORE_CRITICAL | X509_V_FLAG_CRL_CHECK);
+       X509_STORE_CTX_set0_crls(ctx, crls);
+
+       if (X509_verify_cert(ctx) <= 0) {
+               c = X509_STORE_CTX_get_error(ctx);
+               if (verbose > 0 || c != X509_V_ERR_UNABLE_TO_GET_CRL)
+                       warnx("%s: %s", entp->uri,
+                           X509_verify_cert_error_string(c));
+       }
+
+       X509_STORE_CTX_cleanup(ctx);
+       sk_X509_free(chain);
+       sk_X509_CRL_free(crls);
+       X509_free(x509);
+       gbr_free(gbr);
+}
+
 /* use the parent (id) to walk the tree to the root and
    build a certificate chain from cert->x509 */
 static void
@@ -1129,6 +1193,9 @@ proc_parser(int fd)
                                roa_buffer(&b, &bsz, &bmax, roa);
                        roa_free(roa);
                        break;
+               case RTYPE_GBR:
+                       proc_parser_gbr(entp, store, ctx, &auths, &crlt);
+                       break;
                default:
                        abort();
                }
@@ -1236,6 +1303,9 @@ entity_process(int proc, int rsync, stru
                        st->roas_invalid++;
                roa_free(roa);
                break;
+       case RTYPE_GBR:
+               st->gbrs++;
+               break;
        default:
                abort();
        }
@@ -1696,6 +1766,7 @@ main(int argc, char *argv[])
        logx("Manifests: %zu (%zu failed parse, %zu stale)",
            stats.mfts, stats.mfts_fail, stats.mfts_stale);
        logx("Certificate revocation lists: %zu", stats.crls);
+       logx("Ghostbuster records: %zu", stats.gbrs);
        logx("Repositories: %zu", stats.repos);
        logx("Files removed: %zu", stats.del_files);
        logx("VRP Entries: %zu (%zu unique)", stats.vrps, stats.uniqs);
Index: mft.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v
retrieving revision 1.19
diff -u -p -r1.19 mft.c
--- mft.c       6 Nov 2020 04:22:18 -0000       1.19
+++ mft.c       7 Dec 2020 20:47:53 -0000
@@ -171,16 +171,6 @@ mft_parse_filehash(struct parse *p, cons
                goto out;
        }
 
-       if (strcasecmp(fn + sz - 4, ".roa") &&
-           strcasecmp(fn + sz - 4, ".crl") &&
-           strcasecmp(fn + sz - 4, ".cer")) {
-               /* ignore unknown files */
-               free(fn);
-               fn = NULL;
-               rc = 1;
-               goto out;
-       }
-
        /* Now hash value. */
 
        hash = sk_ASN1_TYPE_value(seq, 1);
Index: output-json.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/output-json.c,v
retrieving revision 1.13
diff -u -p -r1.13 output-json.c
--- output-json.c       12 Sep 2020 15:46:48 -0000      1.13
+++ output-json.c       7 Dec 2020 21:57:46 -0000
@@ -55,6 +55,7 @@ outputheader_json(FILE *out, struct stat
            "\t\t\"failedmanifests\": %zu,\n"
            "\t\t\"stalemanifests\": %zu,\n"
            "\t\t\"crls\": %zu,\n"
+           "\t\t\"gbrs\": %zu,\n"
            "\t\t\"repositories\": %zu,\n"
            "\t\t\"vrps\": %zu,\n"
            "\t\t\"uniquevrps\": %zu\n"
@@ -66,6 +67,7 @@ outputheader_json(FILE *out, struct stat
            st->tals, st->talnames,
            st->mfts, st->mfts_fail, st->mfts_stale,
            st->crls,
+           st->gbrs,
            st->repos,
            st->vrps, st->uniqs) < 0)
                return -1;
Index: output.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/output.c,v
retrieving revision 1.18
diff -u -p -r1.18 output.c
--- output.c    6 Nov 2020 05:42:43 -0000       1.18
+++ output.c    7 Dec 2020 21:46:16 -0000
@@ -191,6 +191,7 @@ outputheader(FILE *out, struct stats *st
            "# Trust Anchor Locators: %zu (%s)\n"
            "# Manifests: %zu (%zu failed parse, %zu stale)\n"
            "# Certificate revocation lists: %zu\n"
+           "# Ghostbuster records: %zu\n"
            "# Repositories: %zu\n"
            "# VRP Entries: %zu (%zu unique)\n",
            hn, tbuf, (long long)st->elapsed_time.tv_sec,
@@ -200,6 +201,7 @@ outputheader(FILE *out, struct stats *st
            st->tals, st->talnames,
            st->mfts, st->mfts_fail, st->mfts_stale,
            st->crls,
+           st->gbrs,
            st->repos,
            st->vrps, st->uniqs) < 0)
                return -1;

Reply via email to