mirror of
https://github.com/openbsd/src.git
synced 2025-01-09 22:38:01 -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:
parent
577ce9cf68
commit
6b83d8e365
@ -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>
|
||||
*
|
||||
* 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. */
|
||||
|
||||
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) {
|
||||
warnx("%s: RFC 6487 section 8.4.2: missing SKI", p.fn);
|
||||
goto out;
|
||||
@ -1105,29 +1137,6 @@ cert_parse_inner(X509 **xp, const char *fn, int ta)
|
||||
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)
|
||||
errx(1, "%s: X509_up_ref failed", __func__);
|
||||
|
||||
@ -1207,6 +1216,8 @@ cert_free(struct cert *p)
|
||||
free(p->aia);
|
||||
free(p->aki);
|
||||
free(p->ski);
|
||||
free(p->tal);
|
||||
free(p->bgpsec_pubkey);
|
||||
X509_free(p->x509);
|
||||
free(p);
|
||||
}
|
||||
@ -1249,6 +1260,7 @@ cert_buffer(struct ibuf *b, const struct cert *p)
|
||||
size_t i;
|
||||
|
||||
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->ipsz, sizeof(size_t));
|
||||
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->aki);
|
||||
io_str_buffer(b, p->ski);
|
||||
io_str_buffer(b, p->tal);
|
||||
io_str_buffer(b, p->bgpsec_pubkey);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1311,6 +1325,7 @@ cert_read(int fd)
|
||||
err(1, NULL);
|
||||
|
||||
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->ipsz, sizeof(size_t));
|
||||
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->ski);
|
||||
assert(p->ski);
|
||||
io_str_read(fd, &p->tal);
|
||||
io_str_read(fd, &p->bgpsec_pubkey);
|
||||
|
||||
return p;
|
||||
}
|
||||
@ -1359,3 +1376,78 @@ authcmp(struct auth *a, struct auth *b)
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -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>
|
||||
*
|
||||
@ -102,7 +102,8 @@ struct cert_ip {
|
||||
};
|
||||
|
||||
enum cert_purpose {
|
||||
CERT_PURPOSE_CA = 1,
|
||||
CERT_PURPOSE_INVALID,
|
||||
CERT_PURPOSE_CA,
|
||||
CERT_PURPOSE_BGPSEC_ROUTER
|
||||
};
|
||||
|
||||
@ -124,7 +125,9 @@ struct cert {
|
||||
char *aia; /* AIA (or NULL, for trust anchor) */
|
||||
char *aki; /* AKI (or NULL, for trust anchor) */
|
||||
char *ski; /* SKI */
|
||||
char *tal; /* basename of TAL for this cert */
|
||||
enum cert_purpose purpose; /* Certificate Purpose (BGPSec or CA) */
|
||||
char *bgpsec_pubkey; /* BGPsec Router Key */
|
||||
int valid; /* validated resources */
|
||||
X509 *x509; /* the cert */
|
||||
time_t expires; /* do not use after */
|
||||
@ -226,6 +229,22 @@ struct vrp {
|
||||
RB_HEAD(vrp_tree, vrp);
|
||||
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
|
||||
*/
|
||||
@ -359,8 +378,8 @@ struct stats {
|
||||
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 */
|
||||
size_t brks; /* number of BGPsec Router Key (BRK) certificates */
|
||||
size_t brks_invalids; /* invalid BGPsec certs */
|
||||
char *talnames;
|
||||
struct timeval elapsed_time;
|
||||
struct timeval user_time;
|
||||
@ -385,6 +404,7 @@ void cert_free(struct cert *);
|
||||
struct cert *cert_parse(X509 **, const char *);
|
||||
struct cert *ta_parse(X509 **, const char *, const unsigned char *, size_t);
|
||||
struct cert *cert_read(int);
|
||||
void cert_insert_brks(struct brk_tree *, struct cert *);
|
||||
|
||||
void mft_buffer(struct ibuf *, const struct mft *);
|
||||
void mft_free(struct mft *);
|
||||
@ -525,13 +545,13 @@ int io_recvfd(int, void *, size_t);
|
||||
|
||||
/* X509 helpers. */
|
||||
|
||||
char *hex_encode(const unsigned char *, size_t);
|
||||
char *x509_get_aia(X509 *, const char *);
|
||||
char *x509_get_aki(X509 *, int, const char *);
|
||||
char *x509_get_ski(X509 *, const char *);
|
||||
time_t x509_get_expire(X509 *, const char *);
|
||||
char *x509_get_crl(X509 *, 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 *);
|
||||
|
||||
/* Output! */
|
||||
@ -542,14 +562,21 @@ extern int outformats;
|
||||
#define FORMAT_CSV 0x04
|
||||
#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 output_bgpd(FILE *, struct vrp_tree *, struct stats *);
|
||||
int output_bird1v4(FILE *, struct vrp_tree *, struct stats *);
|
||||
int output_bird1v6(FILE *, struct vrp_tree *, struct stats *);
|
||||
int output_bird2(FILE *, struct vrp_tree *, struct stats *);
|
||||
int output_csv(FILE *, struct vrp_tree *, struct stats *);
|
||||
int output_json(FILE *, struct vrp_tree *, struct stats *);
|
||||
int output_bgpd(FILE *, struct vrp_tree *, struct brk_tree *,
|
||||
struct stats *);
|
||||
int output_bird1v4(FILE *, struct vrp_tree *, struct brk_tree *,
|
||||
struct stats *);
|
||||
int output_bird1v6(FILE *, struct vrp_tree *, struct brk_tree *,
|
||||
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, ...)
|
||||
__attribute__((format(printf, 1, 2)));
|
||||
|
@ -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>
|
||||
*
|
||||
@ -465,9 +465,10 @@ queue_add_from_cert(const struct cert *cert)
|
||||
* In all cases, we gather statistics.
|
||||
*/
|
||||
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 cert *cert;
|
||||
struct mft *mft;
|
||||
@ -509,10 +510,11 @@ entity_process(int proc, struct stats *st, struct vrp_tree *tree)
|
||||
} else
|
||||
st->certs_invalid++;
|
||||
} else if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER) {
|
||||
if (cert->valid)
|
||||
st->bgpsec_routers++;
|
||||
else
|
||||
st->bgpsec_invalids++;
|
||||
if (cert->valid) {
|
||||
cert_insert_brks(brktree, cert);
|
||||
st->brks++;
|
||||
} else
|
||||
st->brks_invalids++;
|
||||
} else
|
||||
st->certs_invalid++;
|
||||
cert_free(cert);
|
||||
@ -637,6 +639,7 @@ main(int argc, char *argv[])
|
||||
const char *cachedir = NULL, *outputdir = NULL;
|
||||
const char *tals[TALSZ_MAX], *errs, *name;
|
||||
struct vrp_tree v = RB_INITIALIZER(&v);
|
||||
struct brk_tree b = RB_INITIALIZER(&b);
|
||||
struct rusage ru;
|
||||
struct timeval start_time, now_time;
|
||||
|
||||
@ -1076,7 +1079,7 @@ main(int argc, char *argv[])
|
||||
*/
|
||||
|
||||
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)
|
||||
err(1, "fchdir output dir");
|
||||
|
||||
if (outputfiles(&v, &stats))
|
||||
if (outputfiles(&v, &b, &stats))
|
||||
rc = 1;
|
||||
|
||||
|
||||
@ -1166,7 +1169,7 @@ main(int argc, char *argv[])
|
||||
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);
|
||||
stats.brks, stats.brks_invalids);
|
||||
logx("Repositories: %zu", stats.repos);
|
||||
logx("Cleanup: removed %zu files, %zu directories",
|
||||
stats.del_files, stats.del_dirs);
|
||||
|
@ -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>
|
||||
*
|
||||
@ -20,7 +20,8 @@
|
||||
#include "extern.h"
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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) 2020 Robert Scheck <robert@fedoraproject.org>
|
||||
@ -21,7 +21,8 @@
|
||||
#include "extern.h"
|
||||
|
||||
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;
|
||||
struct vrp *v;
|
||||
@ -49,7 +50,8 @@ output_bird1v4(FILE *out, struct vrp_tree *vrps, struct stats *st)
|
||||
}
|
||||
|
||||
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;
|
||||
struct vrp *v;
|
||||
@ -77,7 +79,8 @@ output_bird1v6(FILE *out, struct vrp_tree *vrps, struct stats *st)
|
||||
}
|
||||
|
||||
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;
|
||||
struct vrp *v;
|
||||
|
@ -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>
|
||||
*
|
||||
@ -20,7 +20,8 @@
|
||||
#include "extern.h"
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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>
|
||||
*
|
||||
@ -46,6 +46,8 @@ outputheader_json(FILE *out, struct stats *st)
|
||||
"\t\t\"roas\": %zu,\n"
|
||||
"\t\t\"failedroas\": %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\"failcertificates\": %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,
|
||||
(long long)st->user_time.tv_sec, (long long)st->system_time.tv_sec,
|
||||
st->roas, st->roas_fail, st->roas_invalid,
|
||||
st->brks, st->brks_invalids,
|
||||
st->certs, st->certs_fail, st->certs_invalid,
|
||||
st->tals, st->talnames,
|
||||
st->mfts, st->mfts_fail, st->mfts_stale,
|
||||
@ -78,10 +81,12 @@ outputheader_json(FILE *out, struct stats *st)
|
||||
}
|
||||
|
||||
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];
|
||||
struct vrp *v;
|
||||
struct brk *b;
|
||||
int first = 1;
|
||||
|
||||
if (outputheader_json(out, st) < 0)
|
||||
@ -91,12 +96,11 @@ output_json(FILE *out, struct vrp_tree *vrps, struct stats *st)
|
||||
return -1;
|
||||
|
||||
RB_FOREACH(v, vrp_tree, vrps) {
|
||||
if (first)
|
||||
first = 0;
|
||||
else {
|
||||
if (!first) {
|
||||
if (fprintf(out, ",\n") < 0)
|
||||
return -1;
|
||||
}
|
||||
first = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
return -1;
|
||||
return 0;
|
||||
|
@ -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>
|
||||
*
|
||||
@ -64,7 +64,8 @@ static char output_name[PATH_MAX];
|
||||
static const struct outputs {
|
||||
int format;
|
||||
char *name;
|
||||
int (*fn)(FILE *, struct vrp_tree *, struct stats *);
|
||||
int (*fn)(FILE *, struct vrp_tree *, struct brk_tree *,
|
||||
struct stats *);
|
||||
} outputs[] = {
|
||||
{ FORMAT_OPENBGPD, "openbgpd", output_bgpd },
|
||||
{ FORMAT_BIRD, "bird1v4", output_bird1v4 },
|
||||
@ -82,7 +83,7 @@ static void sig_handler(int);
|
||||
static void set_signal_handler(void);
|
||||
|
||||
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;
|
||||
|
||||
@ -101,7 +102,7 @@ outputfiles(struct vrp_tree *v, struct stats *st)
|
||||
rc = 1;
|
||||
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);
|
||||
fclose(fout);
|
||||
output_cleantmp();
|
||||
@ -212,6 +213,7 @@ outputheader(FILE *out, struct stats *st)
|
||||
"# Generated on host %s at %s\n"
|
||||
"# Processing time %lld seconds (%lld seconds user, %lld seconds system)\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"
|
||||
"# Trust Anchor Locators: %zu (%s)\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,
|
||||
(long long)st->user_time.tv_sec, (long long)st->system_time.tv_sec,
|
||||
st->roas, st->roas_fail, st->roas_invalid,
|
||||
st->brks, st->brks_invalids,
|
||||
st->certs, st->certs_fail, st->certs_invalid,
|
||||
st->tals, st->talnames,
|
||||
st->mfts, st->mfts_fail, st->mfts_stale,
|
||||
|
@ -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 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
@ -194,7 +194,6 @@ proc_parser_cert(const struct entity *entp, X509_STORE_CTX *ctx,
|
||||
X509 *x509;
|
||||
int c;
|
||||
struct auth *a = NULL, *na;
|
||||
char *tal;
|
||||
STACK_OF(X509) *chain;
|
||||
STACK_OF(X509_CRL) *crls;
|
||||
|
||||
@ -252,11 +251,13 @@ proc_parser_cert(const struct entity *entp, X509_STORE_CTX *ctx,
|
||||
if (na == NULL)
|
||||
err(1, NULL);
|
||||
|
||||
tal = a->tal;
|
||||
cert->tal = strdup(a->tal);
|
||||
if (cert->tal == NULL)
|
||||
err(1, NULL);
|
||||
|
||||
na->parent = a;
|
||||
na->cert = cert;
|
||||
na->tal = tal;
|
||||
na->tal = a->tal;
|
||||
na->fn = strdup(entp->file);
|
||||
if (na->fn == NULL)
|
||||
err(1, NULL);
|
||||
|
@ -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>
|
||||
.\"
|
||||
@ -14,7 +14,7 @@
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" 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
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -237,6 +237,9 @@ The Resource Public Key Infrastructure (RPKI) Ghostbusters Record.
|
||||
Resource Public Key Infrastructure (RPKI) Trust Anchor Locator.
|
||||
.It RFC 8182
|
||||
The RPKI Repository Delta Protocol (RRDP).
|
||||
.It RFC 8209
|
||||
A Profile for BGPsec Router Certificates, Certificate Revocation Lists, and
|
||||
Certification Requests.
|
||||
.El
|
||||
.\" .Sh HISTORY
|
||||
.Sh AUTHORS
|
||||
|
@ -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>
|
||||
*
|
||||
@ -163,8 +163,11 @@ valid_cert(const char *fn, struct auth_tree *auths, const struct cert *cert)
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
min = cert->as[i].type == CERT_AS_ID ?
|
||||
cert->as[i].id : cert->as[i].range.min;
|
||||
max = cert->as[i].type == CERT_AS_ID ?
|
||||
|
@ -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>
|
||||
*
|
||||
@ -24,6 +24,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
#include "extern.h"
|
||||
@ -88,6 +89,7 @@ x509_get_aki(X509 *x, int ta, const char *fn)
|
||||
}
|
||||
|
||||
res = hex_encode(d, dsz);
|
||||
|
||||
out:
|
||||
AUTHORITY_KEYID_free(akid);
|
||||
return res;
|
||||
@ -177,6 +179,64 @@ x509_get_purpose(X509 *x, const char *fn)
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user