1
0
mirror of https://github.com/openbsd/src.git synced 2025-01-10 06:47:55 -08:00

Add support for BGPsec Router Certificates (RFC 8209)

BGPsec router keys are extracted from RPKI certificates and
emitted via the JSON output in base64 encoded form.

OK tb@ claudio@
This commit is contained in:
job 2021-10-11 16:50:03 +00:00
parent 577ce9cf68
commit 6b83d8e365
12 changed files with 290 additions and 72 deletions

View File

@ -1,5 +1,6 @@
/* $OpenBSD: cert.c,v 1.36 2021/10/07 12:59:29 job Exp $ */ /* $OpenBSD: cert.c,v 1.37 2021/10/11 16:50:03 job Exp $ */
/* /*
* Copyright (c) 2021 Job Snijders <job@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
@ -1068,6 +1069,37 @@ cert_parse_inner(X509 **xp, const char *fn, int ta)
/* Validation on required fields. */ /* Validation on required fields. */
switch (p.res->purpose) {
case CERT_PURPOSE_CA:
if (p.res->mft == NULL) {
warnx("%s: RFC 6487 section 4.8.8: missing SIA", p.fn);
goto out;
}
if (p.res->asz == 0 && p.res->ipsz == 0) {
warnx("%s: missing IP or AS resources", p.fn);
goto out;
}
break;
case CERT_PURPOSE_BGPSEC_ROUTER:
p.res->bgpsec_pubkey = x509_get_bgpsec_pubkey(x, p.fn);
if (p.res->bgpsec_pubkey == NULL) {
warnx("%s: x509_get_bgpsec_pubkey failed", p.fn);
goto out;
}
if (p.res->ipsz > 0) {
warnx("%s: unexpected IP resources in BGPsec cert", p.fn);
goto out;
}
if (sia_present) {
warnx("%s: unexpected SIA extension in BGPsec cert", p.fn);
goto out;
}
break;
default:
warnx("%s: x509_get_purpose failed in %s", p.fn, __func__);
goto out;
}
if (p.res->ski == NULL) { 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;
@ -1105,29 +1137,6 @@ cert_parse_inner(X509 **xp, const char *fn, int ta)
goto out; goto out;
} }
if (p.res->asz == 0 && p.res->ipsz == 0) {
warnx("%s: RFC 6487 section 4.8.10 and 4.8.11: "
"missing IP or AS resources", p.fn);
goto out;
}
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_BGPSEC_ROUTER && sia_present) {
warnx("%s: BGPsec Router Certificate must not have SIA", 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;
}
if (X509_up_ref(x) == 0) if (X509_up_ref(x) == 0)
errx(1, "%s: X509_up_ref failed", __func__); errx(1, "%s: X509_up_ref failed", __func__);
@ -1207,6 +1216,8 @@ cert_free(struct cert *p)
free(p->aia); free(p->aia);
free(p->aki); free(p->aki);
free(p->ski); free(p->ski);
free(p->tal);
free(p->bgpsec_pubkey);
X509_free(p->x509); X509_free(p->x509);
free(p); free(p);
} }
@ -1249,6 +1260,7 @@ cert_buffer(struct ibuf *b, const struct cert *p)
size_t i; size_t i;
io_simple_buffer(b, &p->valid, sizeof(int)); io_simple_buffer(b, &p->valid, sizeof(int));
io_simple_buffer(b, &p->expires, sizeof(time_t));
io_simple_buffer(b, &p->purpose, sizeof(enum cert_purpose)); io_simple_buffer(b, &p->purpose, sizeof(enum cert_purpose));
io_simple_buffer(b, &p->ipsz, sizeof(size_t)); io_simple_buffer(b, &p->ipsz, sizeof(size_t));
for (i = 0; i < p->ipsz; i++) for (i = 0; i < p->ipsz; i++)
@ -1264,6 +1276,8 @@ cert_buffer(struct ibuf *b, const struct cert *p)
io_str_buffer(b, p->aia); io_str_buffer(b, p->aia);
io_str_buffer(b, p->aki); io_str_buffer(b, p->aki);
io_str_buffer(b, p->ski); io_str_buffer(b, p->ski);
io_str_buffer(b, p->tal);
io_str_buffer(b, p->bgpsec_pubkey);
} }
static void static void
@ -1311,6 +1325,7 @@ cert_read(int fd)
err(1, NULL); err(1, NULL);
io_simple_read(fd, &p->valid, sizeof(int)); io_simple_read(fd, &p->valid, sizeof(int));
io_simple_read(fd, &p->expires, sizeof(time_t));
io_simple_read(fd, &p->purpose, sizeof(enum cert_purpose)); io_simple_read(fd, &p->purpose, sizeof(enum cert_purpose));
io_simple_read(fd, &p->ipsz, sizeof(size_t)); io_simple_read(fd, &p->ipsz, sizeof(size_t));
p->ips = calloc(p->ipsz, sizeof(struct cert_ip)); p->ips = calloc(p->ipsz, sizeof(struct cert_ip));
@ -1335,6 +1350,8 @@ cert_read(int fd)
io_str_read(fd, &p->aki); io_str_read(fd, &p->aki);
io_str_read(fd, &p->ski); io_str_read(fd, &p->ski);
assert(p->ski); assert(p->ski);
io_str_read(fd, &p->tal);
io_str_read(fd, &p->bgpsec_pubkey);
return p; return p;
} }
@ -1359,3 +1376,78 @@ authcmp(struct auth *a, struct auth *b)
} }
RB_GENERATE(auth_tree, auth, entry, authcmp); RB_GENERATE(auth_tree, auth, entry, authcmp);
/*
* Extract
*/
static void
insert_brk(struct brk_tree *tree, struct cert *cert, int asid)
{
struct brk *b, *found;
if ((b = calloc(1, sizeof(*b))) == NULL)
err(1, NULL);
b->asid = asid;
b->expires = cert->expires;
if ((b->key = strdup(cert->bgpsec_pubkey)) == NULL)
err(1, NULL);
if ((b->tal = strdup(cert->tal)) == NULL)
err(1, NULL);
/*
* Check if a similar BRK already exists in the tree. If the found BRK
* expires sooner, update it to this BRK's later expiry moment.
*/
if ((found = RB_INSERT(brk_tree, tree, b)) != NULL) {
/* already exists */
if (found->expires < b->expires) {
/* update found with preferred data */
found->expires = b->expires;
free(found->tal);
found->tal = b->tal;
b->tal = NULL;
}
free(b->key);
free(b->tal);
free(b);
}
}
/*
* Add each BGPsec Router Key into the BRK tree.
*/
void
cert_insert_brks(struct brk_tree *tree, struct cert *cert)
{
size_t i, asid;
for (i = 0; i < cert->asz; i++) {
switch (cert->as[i].type) {
case CERT_AS_ID:
insert_brk(tree, cert, cert->as[i].id);
break;
case CERT_AS_RANGE:
for (asid = cert->as[i].range.min;
asid <= cert->as[i].range.max; asid++)
insert_brk(tree, cert, asid);
break;
default:
warnx("invalid AS identifier type");
continue;
}
}
}
static inline int
brkcmp(struct brk *a, struct brk *b)
{
if (a->asid > b->asid)
return 1;
if (a->asid < b->asid)
return -1;
return strcmp(a->key, b->key);
}
RB_GENERATE(brk_tree, brk, entry, brkcmp);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: extern.h,v 1.70 2021/10/10 21:57:43 job Exp $ */ /* $OpenBSD: extern.h,v 1.71 2021/10/11 16:50:03 job Exp $ */
/* /*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
* *
@ -102,7 +102,8 @@ struct cert_ip {
}; };
enum cert_purpose { enum cert_purpose {
CERT_PURPOSE_CA = 1, CERT_PURPOSE_INVALID,
CERT_PURPOSE_CA,
CERT_PURPOSE_BGPSEC_ROUTER CERT_PURPOSE_BGPSEC_ROUTER
}; };
@ -124,7 +125,9 @@ struct cert {
char *aia; /* AIA (or NULL, for trust anchor) */ char *aia; /* AIA (or NULL, for trust anchor) */
char *aki; /* AKI (or NULL, for trust anchor) */ char *aki; /* AKI (or NULL, for trust anchor) */
char *ski; /* SKI */ char *ski; /* SKI */
char *tal; /* basename of TAL for this cert */
enum cert_purpose purpose; /* Certificate Purpose (BGPSec or CA) */ enum cert_purpose purpose; /* Certificate Purpose (BGPSec or CA) */
char *bgpsec_pubkey; /* BGPsec Router Key */
int valid; /* validated resources */ int valid; /* validated resources */
X509 *x509; /* the cert */ X509 *x509; /* the cert */
time_t expires; /* do not use after */ time_t expires; /* do not use after */
@ -226,6 +229,22 @@ struct vrp {
RB_HEAD(vrp_tree, vrp); RB_HEAD(vrp_tree, vrp);
RB_PROTOTYPE(vrp_tree, vrp, entry, vrpcmp); RB_PROTOTYPE(vrp_tree, vrp, entry, vrpcmp);
/*
* A single BGPsec Router Key (including ASID)
*/
struct brk {
RB_ENTRY(brk) entry;
uint32_t asid;
char *tal; /* basename of TAL for this key */
uint8_t *key; /* raw P-256 ECDSA public key */
time_t expires; /* transitive expiry moment */
};
/*
* Tree of BRK sorted by asid
*/
RB_HEAD(brk_tree, brk);
RB_PROTOTYPE(brk_tree, brk, entry, brkcmp);
/* /*
* A single CRL * A single CRL
*/ */
@ -359,8 +378,8 @@ struct stats {
size_t uniqs; /* number of unique vrps */ size_t uniqs; /* number of unique vrps */
size_t del_files; /* number of files removed in cleanup */ size_t del_files; /* number of files removed in cleanup */
size_t del_dirs; /* number of directories removed in cleanup */ size_t del_dirs; /* number of directories removed in cleanup */
size_t bgpsec_routers; /* number of BGPsec Router certs */ size_t brks; /* number of BGPsec Router Key (BRK) certificates */
size_t bgpsec_invalids; /* invalid bgpsec router certs */ size_t brks_invalids; /* invalid BGPsec certs */
char *talnames; char *talnames;
struct timeval elapsed_time; struct timeval elapsed_time;
struct timeval user_time; struct timeval user_time;
@ -385,6 +404,7 @@ void cert_free(struct cert *);
struct cert *cert_parse(X509 **, const char *); struct cert *cert_parse(X509 **, const char *);
struct cert *ta_parse(X509 **, const char *, const unsigned char *, size_t); struct cert *ta_parse(X509 **, const char *, const unsigned char *, size_t);
struct cert *cert_read(int); struct cert *cert_read(int);
void cert_insert_brks(struct brk_tree *, struct cert *);
void mft_buffer(struct ibuf *, const struct mft *); void mft_buffer(struct ibuf *, const struct mft *);
void mft_free(struct mft *); void mft_free(struct mft *);
@ -525,13 +545,13 @@ int io_recvfd(int, void *, size_t);
/* X509 helpers. */ /* X509 helpers. */
char *hex_encode(const unsigned char *, size_t);
char *x509_get_aia(X509 *, const char *); char *x509_get_aia(X509 *, const char *);
char *x509_get_aki(X509 *, int, const char *); char *x509_get_aki(X509 *, int, const char *);
char *x509_get_ski(X509 *, const char *); char *x509_get_ski(X509 *, const char *);
time_t x509_get_expire(X509 *, const char *); time_t x509_get_expire(X509 *, const char *);
char *x509_get_crl(X509 *, const char *); char *x509_get_crl(X509 *, const char *);
char *x509_crl_get_aki(X509_CRL *, const char *); char *x509_crl_get_aki(X509_CRL *, const char *);
char *x509_get_bgpsec_pubkey(X509 *, const char *);
enum cert_purpose x509_get_purpose(X509 *, const char *); enum cert_purpose x509_get_purpose(X509 *, const char *);
/* Output! */ /* Output! */
@ -542,14 +562,21 @@ extern int outformats;
#define FORMAT_CSV 0x04 #define FORMAT_CSV 0x04
#define FORMAT_JSON 0x08 #define FORMAT_JSON 0x08
int outputfiles(struct vrp_tree *v, struct stats *); int outputfiles(struct vrp_tree *v, struct brk_tree *b,
struct stats *);
int outputheader(FILE *, struct stats *); int outputheader(FILE *, struct stats *);
int output_bgpd(FILE *, struct vrp_tree *, struct stats *); int output_bgpd(FILE *, struct vrp_tree *, struct brk_tree *,
int output_bird1v4(FILE *, struct vrp_tree *, struct stats *); struct stats *);
int output_bird1v6(FILE *, struct vrp_tree *, struct stats *); int output_bird1v4(FILE *, struct vrp_tree *, struct brk_tree *,
int output_bird2(FILE *, struct vrp_tree *, struct stats *); struct stats *);
int output_csv(FILE *, struct vrp_tree *, struct stats *); int output_bird1v6(FILE *, struct vrp_tree *, struct brk_tree *,
int output_json(FILE *, struct vrp_tree *, struct stats *); struct stats *);
int output_bird2(FILE *, struct vrp_tree *, struct brk_tree *,
struct stats *);
int output_csv(FILE *, struct vrp_tree *, struct brk_tree *,
struct stats *);
int output_json(FILE *, struct vrp_tree *, struct brk_tree *,
struct stats *);
void logx(const char *fmt, ...) void logx(const char *fmt, ...)
__attribute__((format(printf, 1, 2))); __attribute__((format(printf, 1, 2)));

View File

@ -1,4 +1,4 @@
/* $OpenBSD: main.c,v 1.148 2021/10/10 22:04:33 job Exp $ */ /* $OpenBSD: main.c,v 1.149 2021/10/11 16:50:03 job Exp $ */
/* /*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
* *
@ -465,9 +465,10 @@ queue_add_from_cert(const struct cert *cert)
* In all cases, we gather statistics. * In all cases, we gather statistics.
*/ */
static void static void
entity_process(int proc, struct stats *st, struct vrp_tree *tree) entity_process(int proc, struct stats *st, struct vrp_tree *tree,
struct brk_tree *brktree)
{ {
enum rtype type; enum rtype type;
struct tal *tal; struct tal *tal;
struct cert *cert; struct cert *cert;
struct mft *mft; struct mft *mft;
@ -509,10 +510,11 @@ entity_process(int proc, struct stats *st, struct vrp_tree *tree)
} else } else
st->certs_invalid++; st->certs_invalid++;
} else if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER) { } else if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER) {
if (cert->valid) if (cert->valid) {
st->bgpsec_routers++; cert_insert_brks(brktree, cert);
else st->brks++;
st->bgpsec_invalids++; } else
st->brks_invalids++;
} else } else
st->certs_invalid++; st->certs_invalid++;
cert_free(cert); cert_free(cert);
@ -637,6 +639,7 @@ main(int argc, char *argv[])
const char *cachedir = NULL, *outputdir = NULL; const char *cachedir = NULL, *outputdir = NULL;
const char *tals[TALSZ_MAX], *errs, *name; const char *tals[TALSZ_MAX], *errs, *name;
struct vrp_tree v = RB_INITIALIZER(&v); struct vrp_tree v = RB_INITIALIZER(&v);
struct brk_tree b = RB_INITIALIZER(&b);
struct rusage ru; struct rusage ru;
struct timeval start_time, now_time; struct timeval start_time, now_time;
@ -1076,7 +1079,7 @@ main(int argc, char *argv[])
*/ */
if ((pfd[0].revents & POLLIN)) { if ((pfd[0].revents & POLLIN)) {
entity_process(proc, &stats, &v); entity_process(proc, &stats, &v, &b);
} }
} }
@ -1152,7 +1155,7 @@ main(int argc, char *argv[])
if (fchdir(outdirfd) == -1) if (fchdir(outdirfd) == -1)
err(1, "fchdir output dir"); err(1, "fchdir output dir");
if (outputfiles(&v, &stats)) if (outputfiles(&v, &b, &stats))
rc = 1; rc = 1;
@ -1166,7 +1169,7 @@ main(int argc, char *argv[])
logx("Certificate revocation lists: %zu", stats.crls); logx("Certificate revocation lists: %zu", stats.crls);
logx("Ghostbuster records: %zu", stats.gbrs); logx("Ghostbuster records: %zu", stats.gbrs);
logx("BGPsec Router Certificates: %zu (%zu invalid)", logx("BGPsec Router Certificates: %zu (%zu invalid)",
stats.bgpsec_routers, stats.bgpsec_invalids); stats.brks, stats.brks_invalids);
logx("Repositories: %zu", stats.repos); logx("Repositories: %zu", stats.repos);
logx("Cleanup: removed %zu files, %zu directories", logx("Cleanup: removed %zu files, %zu directories",
stats.del_files, stats.del_dirs); stats.del_files, stats.del_dirs);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: output-bgpd.c,v 1.22 2021/09/01 15:21:10 job Exp $ */ /* $OpenBSD: output-bgpd.c,v 1.23 2021/10/11 16:50:03 job Exp $ */
/* /*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
* *
@ -20,7 +20,8 @@
#include "extern.h" #include "extern.h"
int int
output_bgpd(FILE *out, struct vrp_tree *vrps, struct stats *st) output_bgpd(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks,
struct stats *st)
{ {
struct vrp *v; struct vrp *v;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: output-bird.c,v 1.11 2021/04/19 17:04:35 deraadt Exp $ */ /* $OpenBSD: output-bird.c,v 1.12 2021/10/11 16:50:03 job Exp $ */
/* /*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2020 Robert Scheck <robert@fedoraproject.org> * Copyright (c) 2020 Robert Scheck <robert@fedoraproject.org>
@ -21,7 +21,8 @@
#include "extern.h" #include "extern.h"
int int
output_bird1v4(FILE *out, struct vrp_tree *vrps, struct stats *st) output_bird1v4(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks,
struct stats *st)
{ {
extern const char *bird_tablename; extern const char *bird_tablename;
struct vrp *v; struct vrp *v;
@ -49,7 +50,8 @@ output_bird1v4(FILE *out, struct vrp_tree *vrps, struct stats *st)
} }
int int
output_bird1v6(FILE *out, struct vrp_tree *vrps, struct stats *st) output_bird1v6(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks,
struct stats *st)
{ {
extern const char *bird_tablename; extern const char *bird_tablename;
struct vrp *v; struct vrp *v;
@ -77,7 +79,8 @@ output_bird1v6(FILE *out, struct vrp_tree *vrps, struct stats *st)
} }
int int
output_bird2(FILE *out, struct vrp_tree *vrps, struct stats *st) output_bird2(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks,
struct stats *st)
{ {
extern const char *bird_tablename; extern const char *bird_tablename;
struct vrp *v; struct vrp *v;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: output-csv.c,v 1.10 2021/05/06 17:03:57 job Exp $ */ /* $OpenBSD: output-csv.c,v 1.11 2021/10/11 16:50:03 job Exp $ */
/* /*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
* *
@ -20,7 +20,8 @@
#include "extern.h" #include "extern.h"
int int
output_csv(FILE *out, struct vrp_tree *vrps, struct stats *st) output_csv(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks,
struct stats *st)
{ {
struct vrp *v; struct vrp *v;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: output-json.c,v 1.17 2021/05/06 17:03:57 job Exp $ */ /* $OpenBSD: output-json.c,v 1.18 2021/10/11 16:50:03 job Exp $ */
/* /*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
* *
@ -46,6 +46,8 @@ outputheader_json(FILE *out, struct stats *st)
"\t\t\"roas\": %zu,\n" "\t\t\"roas\": %zu,\n"
"\t\t\"failedroas\": %zu,\n" "\t\t\"failedroas\": %zu,\n"
"\t\t\"invalidroas\": %zu,\n" "\t\t\"invalidroas\": %zu,\n"
"\t\t\"bgpsec_router_keys\": %zu,\n"
"\t\t\"invalidbgpsec_router_keys\": %zu,\n"
"\t\t\"certificates\": %zu,\n" "\t\t\"certificates\": %zu,\n"
"\t\t\"failcertificates\": %zu,\n" "\t\t\"failcertificates\": %zu,\n"
"\t\t\"invalidcertificates\": %zu,\n" "\t\t\"invalidcertificates\": %zu,\n"
@ -65,6 +67,7 @@ outputheader_json(FILE *out, struct stats *st)
hn, tbuf, (long long)st->elapsed_time.tv_sec, hn, tbuf, (long long)st->elapsed_time.tv_sec,
(long long)st->user_time.tv_sec, (long long)st->system_time.tv_sec, (long long)st->user_time.tv_sec, (long long)st->system_time.tv_sec,
st->roas, st->roas_fail, st->roas_invalid, st->roas, st->roas_fail, st->roas_invalid,
st->brks, st->brks_invalids,
st->certs, st->certs_fail, st->certs_invalid, st->certs, st->certs_fail, st->certs_invalid,
st->tals, st->talnames, st->tals, st->talnames,
st->mfts, st->mfts_fail, st->mfts_stale, st->mfts, st->mfts_fail, st->mfts_stale,
@ -78,10 +81,12 @@ outputheader_json(FILE *out, struct stats *st)
} }
int int
output_json(FILE *out, struct vrp_tree *vrps, struct stats *st) output_json(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks,
struct stats *st)
{ {
char buf[64]; char buf[64];
struct vrp *v; struct vrp *v;
struct brk *b;
int first = 1; int first = 1;
if (outputheader_json(out, st) < 0) if (outputheader_json(out, st) < 0)
@ -91,12 +96,11 @@ output_json(FILE *out, struct vrp_tree *vrps, struct stats *st)
return -1; return -1;
RB_FOREACH(v, vrp_tree, vrps) { RB_FOREACH(v, vrp_tree, vrps) {
if (first) if (!first) {
first = 0;
else {
if (fprintf(out, ",\n") < 0) if (fprintf(out, ",\n") < 0)
return -1; return -1;
} }
first = 0;
ip_addr_print(&v->addr, v->afi, buf, sizeof(buf)); ip_addr_print(&v->addr, v->afi, buf, sizeof(buf));
@ -107,6 +111,23 @@ output_json(FILE *out, struct vrp_tree *vrps, struct stats *st)
return -1; return -1;
} }
if (fprintf(out, "\n\t],\n\n\t\"bgpsec_keys\": [\n") < 0)
return -1;
first = 1;
RB_FOREACH(b, brk_tree, brks) {
if (!first) {
if (fprintf(out, ",\n") < 0)
return -1;
}
first = 0;
if (fprintf(out, "\t\t{ \"asn\": %u, \"key\": \"%s\", \"ta\": "
"\"%s\", \"expires\": %lld }", b->asid, b->key, b->tal,
(long long)b->expires) < 0)
return -1;
}
if (fprintf(out, "\n\t]\n}\n") < 0) if (fprintf(out, "\n\t]\n}\n") < 0)
return -1; return -1;
return 0; return 0;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: output.c,v 1.21 2021/03/02 09:08:59 claudio Exp $ */ /* $OpenBSD: output.c,v 1.22 2021/10/11 16:50:03 job Exp $ */
/* /*
* Copyright (c) 2019 Theo de Raadt <deraadt@openbsd.org> * Copyright (c) 2019 Theo de Raadt <deraadt@openbsd.org>
* *
@ -64,7 +64,8 @@ static char output_name[PATH_MAX];
static const struct outputs { static const struct outputs {
int format; int format;
char *name; char *name;
int (*fn)(FILE *, struct vrp_tree *, struct stats *); int (*fn)(FILE *, struct vrp_tree *, struct brk_tree *,
struct stats *);
} outputs[] = { } outputs[] = {
{ FORMAT_OPENBGPD, "openbgpd", output_bgpd }, { FORMAT_OPENBGPD, "openbgpd", output_bgpd },
{ FORMAT_BIRD, "bird1v4", output_bird1v4 }, { FORMAT_BIRD, "bird1v4", output_bird1v4 },
@ -82,7 +83,7 @@ static void sig_handler(int);
static void set_signal_handler(void); static void set_signal_handler(void);
int int
outputfiles(struct vrp_tree *v, struct stats *st) outputfiles(struct vrp_tree *v, struct brk_tree *b, struct stats *st)
{ {
int i, rc = 0; int i, rc = 0;
@ -101,7 +102,7 @@ outputfiles(struct vrp_tree *v, struct stats *st)
rc = 1; rc = 1;
continue; continue;
} }
if ((*outputs[i].fn)(fout, v, st) != 0) { if ((*outputs[i].fn)(fout, v, b, st) != 0) {
warn("output for %s format failed", outputs[i].name); warn("output for %s format failed", outputs[i].name);
fclose(fout); fclose(fout);
output_cleantmp(); output_cleantmp();
@ -212,6 +213,7 @@ outputheader(FILE *out, struct stats *st)
"# Generated on host %s at %s\n" "# Generated on host %s at %s\n"
"# Processing time %lld seconds (%lld seconds user, %lld seconds system)\n" "# Processing time %lld seconds (%lld seconds user, %lld seconds system)\n"
"# Route Origin Authorizations: %zu (%zu failed parse, %zu invalid)\n" "# Route Origin Authorizations: %zu (%zu failed parse, %zu invalid)\n"
"# BGPsec Router Certificates: %zu (%zu invalid)\n"
"# Certificates: %zu (%zu failed parse, %zu invalid)\n" "# Certificates: %zu (%zu failed parse, %zu invalid)\n"
"# Trust Anchor Locators: %zu (%s)\n" "# Trust Anchor Locators: %zu (%s)\n"
"# Manifests: %zu (%zu failed parse, %zu stale)\n" "# Manifests: %zu (%zu failed parse, %zu stale)\n"
@ -222,6 +224,7 @@ outputheader(FILE *out, struct stats *st)
hn, tbuf, (long long)st->elapsed_time.tv_sec, hn, tbuf, (long long)st->elapsed_time.tv_sec,
(long long)st->user_time.tv_sec, (long long)st->system_time.tv_sec, (long long)st->user_time.tv_sec, (long long)st->system_time.tv_sec,
st->roas, st->roas_fail, st->roas_invalid, st->roas, st->roas_fail, st->roas_invalid,
st->brks, st->brks_invalids,
st->certs, st->certs_fail, st->certs_invalid, st->certs, st->certs_fail, st->certs_invalid,
st->tals, st->talnames, st->tals, st->talnames,
st->mfts, st->mfts_fail, st->mfts_stale, st->mfts, st->mfts_fail, st->mfts_stale,

View File

@ -1,4 +1,4 @@
/* $OpenBSD: parser.c,v 1.12 2021/10/07 08:36:17 claudio Exp $ */ /* $OpenBSD: parser.c,v 1.13 2021/10/11 16:50:03 job Exp $ */
/* /*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@ -194,7 +194,6 @@ proc_parser_cert(const struct entity *entp, X509_STORE_CTX *ctx,
X509 *x509; X509 *x509;
int c; int c;
struct auth *a = NULL, *na; struct auth *a = NULL, *na;
char *tal;
STACK_OF(X509) *chain; STACK_OF(X509) *chain;
STACK_OF(X509_CRL) *crls; STACK_OF(X509_CRL) *crls;
@ -252,11 +251,13 @@ proc_parser_cert(const struct entity *entp, X509_STORE_CTX *ctx,
if (na == NULL) if (na == NULL)
err(1, NULL); err(1, NULL);
tal = a->tal; cert->tal = strdup(a->tal);
if (cert->tal == NULL)
err(1, NULL);
na->parent = a; na->parent = a;
na->cert = cert; na->cert = cert;
na->tal = tal; na->tal = a->tal;
na->fn = strdup(entp->file); na->fn = strdup(entp->file);
if (na->fn == NULL) if (na->fn == NULL)
err(1, NULL); err(1, NULL);

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: rpki-client.8,v 1.47 2021/09/01 08:17:37 claudio Exp $ .\" $OpenBSD: rpki-client.8,v 1.48 2021/10/11 16:50:03 job Exp $
.\" .\"
.\" Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> .\" Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
.\" .\"
@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" .\"
.Dd $Mdocdate: September 1 2021 $ .Dd $Mdocdate: October 11 2021 $
.Dt RPKI-CLIENT 8 .Dt RPKI-CLIENT 8
.Os .Os
.Sh NAME .Sh NAME
@ -237,6 +237,9 @@ The Resource Public Key Infrastructure (RPKI) Ghostbusters Record.
Resource Public Key Infrastructure (RPKI) Trust Anchor Locator. Resource Public Key Infrastructure (RPKI) Trust Anchor Locator.
.It RFC 8182 .It RFC 8182
The RPKI Repository Delta Protocol (RRDP). The RPKI Repository Delta Protocol (RRDP).
.It RFC 8209
A Profile for BGPsec Router Certificates, Certificate Revocation Lists, and
Certification Requests.
.El .El
.\" .Sh HISTORY .\" .Sh HISTORY
.Sh AUTHORS .Sh AUTHORS

View File

@ -1,4 +1,4 @@
/* $OpenBSD: validate.c,v 1.15 2021/08/16 10:38:57 jsg Exp $ */ /* $OpenBSD: validate.c,v 1.16 2021/10/11 16:50:03 job Exp $ */
/* /*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
* *
@ -163,8 +163,11 @@ valid_cert(const char *fn, struct auth_tree *auths, const struct cert *cert)
return 0; return 0;
for (i = 0; i < cert->asz; i++) { for (i = 0; i < cert->asz; i++) {
if (cert->as[i].type == CERT_AS_INHERIT) if (cert->as[i].type == CERT_AS_INHERIT) {
if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER)
return 0; /* BGPsec doesn't permit inheriting */
continue; continue;
}
min = cert->as[i].type == CERT_AS_ID ? min = cert->as[i].type == CERT_AS_ID ?
cert->as[i].id : cert->as[i].range.min; cert->as[i].id : cert->as[i].range.min;
max = cert->as[i].type == CERT_AS_ID ? max = cert->as[i].type == CERT_AS_ID ?

View File

@ -1,4 +1,4 @@
/* $OpenBSD: x509.c,v 1.23 2021/10/07 08:30:39 claudio Exp $ */ /* $OpenBSD: x509.c,v 1.24 2021/10/11 16:50:04 job Exp $ */
/* /*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
* *
@ -24,6 +24,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <openssl/evp.h>
#include <openssl/x509v3.h> #include <openssl/x509v3.h>
#include "extern.h" #include "extern.h"
@ -88,6 +89,7 @@ x509_get_aki(X509 *x, int ta, const char *fn)
} }
res = hex_encode(d, dsz); res = hex_encode(d, dsz);
out: out:
AUTHORITY_KEYID_free(akid); AUTHORITY_KEYID_free(akid);
return res; return res;
@ -177,6 +179,64 @@ x509_get_purpose(X509 *x, const char *fn)
return purpose; return purpose;
} }
/*
* Extract ECDSA key from a BGPsec Router Certificate.
* Returns NULL on failure, on success return public key,
*/
char *
x509_get_bgpsec_pubkey(X509 *x, const char *fn)
{
EVP_PKEY *pubkey;
EC_KEY *ec;
int nid;
const char *cname;
int keylen;
uint8_t *key = NULL;
char *res = NULL;
pubkey = X509_get0_pubkey(x);
if (pubkey == NULL) {
warnx("%s: X509_get_pubkey failed in %s", fn, __func__);
goto out;
}
if (EVP_PKEY_base_id(pubkey) != EVP_PKEY_EC) {
warnx("%s: Expected EVP_PKEY_EC, got %d", fn,
EVP_PKEY_base_id(pubkey));
goto out;
}
ec = EVP_PKEY_get0_EC_KEY(pubkey);
if (ec == NULL) {
warnx("%s: Incorrect key type", fn);
goto out;
}
nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
if (nid != NID_X9_62_prime256v1) {
if ((cname = EC_curve_nid2nist(nid)) == NULL)
cname = OBJ_nid2sn(nid);
warnx("%s: Expected P-256, got %s", fn, cname);
goto out;
}
if (!EC_KEY_check_key(ec)) {
warnx("%s: EC_KEY_check_key failed in %s", fn, __func__);
goto out;
}
keylen = i2o_ECPublicKey(ec, &key);
if (keylen <= 0) {
warnx("%s: i2o_ECPublicKey failed in %s", fn, __func__);
goto out;
}
if (base64_encode(key, keylen, &res) == -1)
errx(1, "base64_encode failed in %s", __func__);
out:
free(key);
return res;
}
/* /*
* Parse the Authority Information Access (AIA) extension * Parse the Authority Information Access (AIA) extension