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>
*
* 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);

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>
*
@ -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)));

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>
*
@ -465,7 +465,8 @@ 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;
struct tal *tal;
@ -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);

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>
*
@ -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;

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) 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;

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>
*
@ -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;

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>
*
@ -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;

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>
*
@ -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,

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 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);

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>
.\"
@ -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

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>
*
@ -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 ?

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>
*
@ -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