-/* $OpenBSD: cert.c,v 1.32 2021/09/09 14:15:49 claudio Exp $ */
+/* $OpenBSD: cert.c,v 1.33 2021/10/05 11:20:46 job Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
break;
case NID_subject_key_identifier:
break;
+ case NID_ext_key_usage:
+ break;
default:
/* {
char objn[64];
p.res->aia = x509_get_aia(x, p.fn);
p.res->crl = x509_get_crl(x, p.fn);
}
+ p.res->purpose = x509_get_purpose(x, p.fn);
/* Validation on required fields. */
if (p.res->ski == NULL) {
- warnx("%s: RFC 6487 section 8.4.2: "
- "missing SKI", p.fn);
+ warnx("%s: RFC 6487 section 8.4.2: missing SKI", p.fn);
goto out;
}
goto out;
}
- if (p.res->mft == NULL) {
- warnx("%s: RFC 6487 section 4.8.8: "
- "missing SIA", p.fn);
+ if (p.res->ipsz > 0 &&
+ p.res->purpose == CERT_PURPOSE_BGPSEC_ROUTER) {
+ warnx("%s: BGPsec Router Certificate must not have RFC 3779 IP "
+ "Addresses", p.fn);
+ goto out;
+ }
+
+ if (p.res->purpose == CERT_PURPOSE_CA && p.res->mft == NULL) {
+ warnx("%s: RFC 6487 section 4.8.8: missing SIA", p.fn);
goto out;
}
+
+ /*
+ * XXX: also add opposite check: is any SIA present?
+ */
+
if (X509_up_ref(x) == 0)
errx(1, "king bula");
size_t i;
io_simple_buffer(b, &p->valid, sizeof(int));
+ io_simple_buffer(b, &p->purpose, sizeof(enum cert_purpose));
io_simple_buffer(b, &p->ipsz, sizeof(size_t));
for (i = 0; i < p->ipsz; i++)
cert_ip_buffer(b, &p->ips[i]);
io_simple_buffer(b, &p->asz, sizeof(size_t));
for (i = 0; i < p->asz; i++)
cert_as_buffer(b, &p->as[i]);
-
io_str_buffer(b, p->mft);
io_str_buffer(b, p->notify);
io_str_buffer(b, p->repo);
err(1, NULL);
io_simple_read(fd, &p->valid, sizeof(int));
+ io_simple_read(fd, &p->purpose, sizeof(enum cert_purpose));
io_simple_read(fd, &p->ipsz, sizeof(size_t));
p->ips = calloc(p->ipsz, sizeof(struct cert_ip));
if (p->ips == NULL)
cert_as_read(fd, &p->as[i]);
io_str_read(fd, &p->mft);
- assert(p->mft);
+ assert(p->mft != NULL || p->purpose == CERT_PURPOSE_BGPSEC_ROUTER);
io_str_read(fd, &p->notify);
io_str_read(fd, &p->repo);
io_str_read(fd, &p->crl);
-/* $OpenBSD: extern.h,v 1.67 2021/09/09 14:15:49 claudio Exp $ */
+/* $OpenBSD: extern.h,v 1.68 2021/10/05 11:20:46 job Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
};
};
+enum cert_purpose {
+ CERT_PURPOSE_CA = 1,
+ CERT_PURPOSE_BGPSEC_ROUTER
+};
+
/*
* Parsed components of a validated X509 certificate stipulated by RFC
* 6847 and further (within) by RFC 3779.
char *aia; /* AIA (or NULL, for trust anchor) */
char *aki; /* AKI (or NULL, for trust anchor) */
char *ski; /* SKI */
+ enum cert_purpose purpose; /* Certificate Purpose (BGPSec or CA) */
int valid; /* validated resources */
X509 *x509; /* the cert */
};
size_t uniqs; /* number of unique vrps */
size_t del_files; /* number of files removed in cleanup */
size_t del_dirs; /* number of directories removed in cleanup */
+ size_t bgpsec_routers; /* number of BGPsec Router certs */
+ size_t bgpsec_invalids; /* invalid bgpsec router certs */
char *talnames;
struct timeval elapsed_time;
struct timeval user_time;
char *x509_get_ski(X509 *, const char *);
char *x509_get_crl(X509 *, const char *);
char *x509_crl_get_aki(X509_CRL *, const char *);
+enum cert_purpose x509_get_purpose(X509 *, const char *);
/* Output! */
-/* $OpenBSD: main.c,v 1.145 2021/08/30 16:05:55 job Exp $ */
+/* $OpenBSD: main.c,v 1.146 2021/10/05 11:20:46 job Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
break;
}
cert = cert_read(proc);
- if (cert->valid) {
- /*
- * Process the revocation list from the
- * certificate *first*, since it might mark that
- * we're revoked and then we don't want to
- * process the MFT.
- */
- queue_add_from_cert(cert);
+ if (cert->purpose == CERT_PURPOSE_CA) {
+ if (cert->valid) {
+ /*
+ * Process the revocation list from the
+ * certificate *first*, since it might mark that
+ * we're revoked and then we don't want to
+ * process the MFT.
+ */
+ queue_add_from_cert(cert);
+ } else
+ st->certs_invalid++;
+ } else if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER) {
+ if (cert->valid)
+ st->bgpsec_routers++;
+ else
+ st->bgpsec_invalids++;
} else
st->certs_invalid++;
cert_free(cert);
stats.mfts, stats.mfts_fail, stats.mfts_stale);
logx("Certificate revocation lists: %zu", stats.crls);
logx("Ghostbuster records: %zu", stats.gbrs);
+ logx("BGPsec Router Certificates: %zu (%zu invalid)",
+ stats.bgpsec_routers, stats.bgpsec_invalids);
logx("Repositories: %zu", stats.repos);
logx("Cleanup: removed %zu files, %zu directories",
stats.del_files, stats.del_dirs);
-/* $OpenBSD: x509.c,v 1.21 2021/04/01 06:43:23 claudio Exp $ */
+/* $OpenBSD: x509.c,v 1.22 2021/10/05 11:20:46 job Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
#include "extern.h"
+static ASN1_OBJECT *bgpsec_oid; /* id-kp-bgpsec-router */
+
+static void
+init_oid(void)
+{
+ if ((bgpsec_oid = OBJ_txt2obj("1.3.6.1.5.5.7.3.30", 1)) == NULL)
+ errx(1, "OBJ_txt2obj for %s failed", "1.3.6.1.5.5.7.3.30");
+}
+
/*
* Parse X509v3 authority key identifier (AKI), RFC 6487 sec. 4.8.3.
* Returns the AKI or NULL if it could not be parsed.
return res;
}
+/*
+ * Check the certificate's purpose: CA or BGPsec Router.
+ * Return a member of enum cert_purpose.
+ */
+enum cert_purpose
+x509_get_purpose(X509 *x, const char *fn)
+{
+ EXTENDED_KEY_USAGE *eku = NULL;
+ int crit;
+ enum cert_purpose purpose = 0;
+
+ if (X509_check_ca(x) == 1) {
+ purpose = CERT_PURPOSE_CA;
+ goto out;
+ }
+
+ eku = X509_get_ext_d2i(x, NID_ext_key_usage, &crit, NULL);
+ if (eku == NULL) {
+ warnx("%s: EKU: extension missing", fn);
+ goto out;
+ }
+ if (crit != 0) {
+ warnx("%s: EKU: extension must not be marked critical", fn);
+ goto out;
+ }
+ if (sk_ASN1_OBJECT_num(eku) != 1) {
+ warnx("%s: EKU: expected 1 purpose, have %d", fn,
+ sk_ASN1_OBJECT_num(eku));
+ goto out;
+ }
+
+ if (bgpsec_oid == NULL)
+ init_oid();
+
+ if (OBJ_cmp(bgpsec_oid, sk_ASN1_OBJECT_value(eku, 0)) == 0) {
+ purpose = CERT_PURPOSE_BGPSEC_ROUTER;
+ goto out;
+ }
+
+ out:
+ EXTENDED_KEY_USAGE_free(eku);
+ return purpose;
+}
+
+
/*
* Parse the Authority Information Access (AIA) extension
* See RFC 6487, section 4.8.7 for details.