summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2020-12-09 11:29:05 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2020-12-09 11:29:05 +0000
commit326d9ca56c756a29e19fe4a8ed3ce48ab5660b09 (patch)
treebf73d735d83c9deb95488355b9cc0ad69e4505e5
parentdcb3fadfbd8947301edec86cdc040d5f0adfa73a (diff)
Validate ghostbuster records (RFC 6493) but for now do nothing with the
provided vcard payload. This change verifies the certificate of the .gbr file and makes sure it is valid (like we do for e.g. .roa files). OK job@
-rw-r--r--usr.sbin/rpki-client/Makefile4
-rw-r--r--usr.sbin/rpki-client/extern.h18
-rw-r--r--usr.sbin/rpki-client/gbr.c88
-rw-r--r--usr.sbin/rpki-client/main.c73
-rw-r--r--usr.sbin/rpki-client/output-json.c4
-rw-r--r--usr.sbin/rpki-client/output.c4
6 files changed, 184 insertions, 7 deletions
diff --git a/usr.sbin/rpki-client/Makefile b/usr.sbin/rpki-client/Makefile
index 2065b598963..ba83ccaa3c9 100644
--- a/usr.sbin/rpki-client/Makefile
+++ b/usr.sbin/rpki-client/Makefile
@@ -1,7 +1,7 @@
-# $OpenBSD: Makefile,v 1.14 2019/12/04 12:40:17 deraadt Exp $
+# $OpenBSD: Makefile,v 1.15 2020/12/09 11:29:04 claudio 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
diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h
index 84707f1deaf..8d1510642eb 100644
--- a/usr.sbin/rpki-client/extern.h
+++ b/usr.sbin/rpki-client/extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: extern.h,v 1.35 2020/12/02 15:31:15 claudio Exp $ */
+/* $OpenBSD: extern.h,v 1.36 2020/12/09 11:29:04 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -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 */
@@ -303,6 +314,9 @@ 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 *);
void free_crl(struct crl *);
diff --git a/usr.sbin/rpki-client/gbr.c b/usr.sbin/rpki-client/gbr.c
new file mode 100644
index 00000000000..6c337896c2f
--- /dev/null
+++ b/usr.sbin/rpki-client/gbr.c
@@ -0,0 +1,88 @@
+/* $OpenBSD: gbr.c,v 1.1 2020/12/09 11:29:04 claudio Exp $ */
+/*
+ * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
+ *
+ * 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);
+}
diff --git a/usr.sbin/rpki-client/main.c b/usr.sbin/rpki-client/main.c
index 0ce21f3198f..4e08b0e91a8 100644
--- a/usr.sbin/rpki-client/main.c
+++ b/usr.sbin/rpki-client/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.85 2020/12/02 15:31:15 claudio Exp $ */
+/* $OpenBSD: main.c,v 1.86 2020/12/09 11:29:04 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
@@ -518,6 +518,27 @@ queue_add_from_mft_set(int fd, struct entityq *q, const struct mft *mft,
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, X509_STORE *store,
}
}
+/*
+ * 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, struct stats *st,
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);
diff --git a/usr.sbin/rpki-client/output-json.c b/usr.sbin/rpki-client/output-json.c
index 1c6738a6e59..94fa6026d21 100644
--- a/usr.sbin/rpki-client/output-json.c
+++ b/usr.sbin/rpki-client/output-json.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: output-json.c,v 1.13 2020/09/12 15:46:48 claudio Exp $ */
+/* $OpenBSD: output-json.c,v 1.14 2020/12/09 11:29:04 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
*
@@ -55,6 +55,7 @@ outputheader_json(FILE *out, struct stats *st)
"\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 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;
diff --git a/usr.sbin/rpki-client/output.c b/usr.sbin/rpki-client/output.c
index 7988815f4ab..f2dce29ecb9 100644
--- a/usr.sbin/rpki-client/output.c
+++ b/usr.sbin/rpki-client/output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: output.c,v 1.18 2020/11/06 05:42:43 tb Exp $ */
+/* $OpenBSD: output.c,v 1.19 2020/12/09 11:29:04 claudio Exp $ */
/*
* Copyright (c) 2019 Theo de Raadt <deraadt@openbsd.org>
*
@@ -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;