From 4b5fc138bec9650287034754b81634496289aca4 Mon Sep 17 00:00:00 2001 From: job Date: Mon, 26 Jun 2023 18:39:53 +0000 Subject: [PATCH] Decode and validate ASPA objects following the v1 syntax Through draft-ietf-sidrops-aspa-profile-15, the ASPA profile was made AFI-agnostic. This represents a simplification for both operators and implementers in both the RPKI and BGP layers of the stack. This update changes the JSON structure. No effort was made to simultaneously support ASPA v0 and v1 objects. OK tb@ claudio@ --- usr.sbin/rpki-client/aspa.c | 70 +++++++++--------------------- usr.sbin/rpki-client/extern.h | 11 ++--- usr.sbin/rpki-client/output-bgpd.c | 14 +----- usr.sbin/rpki-client/output-json.c | 31 ++++--------- usr.sbin/rpki-client/print.c | 50 ++++----------------- usr.sbin/rpki-client/rpki-client.8 | 6 +-- 6 files changed, 45 insertions(+), 137 deletions(-) diff --git a/usr.sbin/rpki-client/aspa.c b/usr.sbin/rpki-client/aspa.c index 1fdd3cb8484..07448fabe9f 100644 --- a/usr.sbin/rpki-client/aspa.c +++ b/usr.sbin/rpki-client/aspa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aspa.c,v 1.18 2023/06/07 10:46:34 job Exp $ */ +/* $OpenBSD: aspa.c,v 1.19 2023/06/26 18:39:53 job Exp $ */ /* * Copyright (c) 2022 Job Snijders * Copyright (c) 2022 Theo Buehler @@ -46,33 +46,16 @@ extern ASN1_OBJECT *aspa_oid; * Types and templates for ASPA eContent draft-ietf-sidrops-aspa-profile-08 */ -typedef struct { - ASN1_INTEGER *providerASID; - ASN1_OCTET_STRING *afiLimit; -} ProviderAS; - -DECLARE_STACK_OF(ProviderAS); - -#ifndef DEFINE_STACK_OF -#define sk_ProviderAS_num(sk) SKM_sk_num(ProviderAS, (sk)) -#define sk_ProviderAS_value(sk, i) SKM_sk_value(ProviderAS, (sk), (i)) -#endif - -ASN1_SEQUENCE(ProviderAS) = { - ASN1_SIMPLE(ProviderAS, providerASID, ASN1_INTEGER), - ASN1_OPT(ProviderAS, afiLimit, ASN1_OCTET_STRING), -} ASN1_SEQUENCE_END(ProviderAS); - typedef struct { ASN1_INTEGER *version; ASN1_INTEGER *customerASID; - STACK_OF(ProviderAS) *providers; + STACK_OF(ASN1_INTEGER) *providers; } ASProviderAttestation; ASN1_SEQUENCE(ASProviderAttestation) = { ASN1_EXP_OPT(ASProviderAttestation, version, ASN1_INTEGER, 0), ASN1_SIMPLE(ASProviderAttestation, customerASID, ASN1_INTEGER), - ASN1_SEQUENCE_OF(ASProviderAttestation, providers, ProviderAS), + ASN1_SEQUENCE_OF(ASProviderAttestation, providers, ASN1_INTEGER), } ASN1_SEQUENCE_END(ASProviderAttestation); DECLARE_ASN1_FUNCTIONS(ASProviderAttestation); @@ -83,13 +66,13 @@ IMPLEMENT_ASN1_FUNCTIONS(ASProviderAttestation); * Return zero on failure, non-zero on success. */ static int -aspa_parse_providers(struct parse *p, const STACK_OF(ProviderAS) *providers) +aspa_parse_providers(struct parse *p, const STACK_OF(ASN1_INTEGER) *providers) { - ProviderAS *pa; - struct aspa_provider provider; + const ASN1_INTEGER *pa; + uint32_t provider; size_t providersz, i; - if ((providersz = sk_ProviderAS_num(providers)) == 0) { + if ((providersz = sk_ASN1_INTEGER_num(providers)) == 0) { warnx("%s: ASPA: ProviderASSet needs at least one entry", p->fn); return 0; @@ -106,39 +89,33 @@ aspa_parse_providers(struct parse *p, const STACK_OF(ProviderAS) *providers) err(1, NULL); for (i = 0; i < providersz; i++) { - pa = sk_ProviderAS_value(providers, i); + pa = sk_ASN1_INTEGER_value(providers, i); memset(&provider, 0, sizeof(provider)); - if (!as_id_parse(pa->providerASID, &provider.as)) { + if (!as_id_parse(pa, &provider)) { warnx("%s: ASPA: malformed ProviderAS", p->fn); return 0; } - if (p->res->custasid == provider.as) { + if (p->res->custasid == provider) { warnx("%s: ASPA: CustomerASID can't also be Provider", p->fn); return 0; } if (i > 0) { - if (p->res->providers[i - 1].as > provider.as) { + if (p->res->providers[i - 1] > provider) { warnx("%s: ASPA: invalid ProviderASSet order", p->fn); return 0; } - if (p->res->providers[i - 1].as == provider.as) { + if (p->res->providers[i - 1] == provider) { warnx("%s: ASPA: duplicate ProviderAS", p->fn); return 0; } } - if (pa->afiLimit != NULL && !ip_addr_afi_parse(p->fn, - pa->afiLimit, &provider.afi)) { - warnx("%s: ASPA: invalid afiLimit", p->fn); - return 0; - } - p->res->providers[p->res->providersz++] = provider; } @@ -161,7 +138,7 @@ aspa_parse_econtent(const unsigned char *d, size_t dsz, struct parse *p) goto out; } - if (!valid_econtent_version(p->fn, aspa->version, 0)) + if (!valid_econtent_version(p->fn, aspa->version, 1)) goto out; if (!as_id_parse(aspa->customerASID, &p->res->custasid)) { @@ -314,8 +291,7 @@ aspa_read(struct ibuf *b) io_read_buf(b, &p->expires, sizeof(p->expires)); io_read_buf(b, &p->providersz, sizeof(size_t)); - if ((p->providers = calloc(p->providersz, - sizeof(struct aspa_provider))) == NULL) + if ((p->providers = calloc(p->providersz, sizeof(uint32_t))) == NULL) err(1, NULL); io_read_buf(b, p->providers, p->providersz * sizeof(p->providers[0])); @@ -328,12 +304,12 @@ aspa_read(struct ibuf *b) } /* - * Insert a new aspa_provider at index idx in the struct vap v. + * Insert a new uint32_t at index idx in the struct vap v. * All elements in the provider array from idx are moved up by one * to make space for the new element. */ static void -insert_vap(struct vap *v, uint32_t idx, struct aspa_provider *p) +insert_vap(struct vap *v, uint32_t idx, uint32_t *p) { if (idx < v->providersz) memmove(v->providers + idx + 1, v->providers + idx, @@ -391,21 +367,15 @@ aspa_insert_vaps(struct vap_tree *tree, struct aspa *aspa, struct repo *rp) */ for (i = 0, j = 0; i < aspa->providersz; ) { if (j == v->providersz || - aspa->providers[i].as < v->providers[j].as) { + aspa->providers[i] < v->providers[j]) { /* merge provider from aspa into v */ repo_stat_inc(rp, v->talid, RTYPE_ASPA, - STYPE_BOTH + aspa->providers[i].afi); + STYPE_BOTH + aspa->providers[i]); insert_vap(v, j, &aspa->providers[i]); i++; - } else if (aspa->providers[i].as == v->providers[j].as) { - /* duplicate provider, merge afi */ - if (v->providers[j].afi != aspa->providers[i].afi) { - repo_stat_inc(rp, v->talid, RTYPE_ASPA, - STYPE_BOTH + aspa->providers[i].afi); - v->providers[j].afi = 0; - } + } else if (aspa->providers[i] == v->providers[j]) i++; - } + if (j < v->providersz) j++; } diff --git a/usr.sbin/rpki-client/extern.h b/usr.sbin/rpki-client/extern.h index abc945c41e4..142442c3783 100644 --- a/usr.sbin/rpki-client/extern.h +++ b/usr.sbin/rpki-client/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.185 2023/06/23 11:36:24 claudio Exp $ */ +/* $OpenBSD: extern.h,v 1.186 2023/06/26 18:39:53 job Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -351,11 +351,6 @@ struct gbr { int talid; /* TAL the GBR is chained up to */ }; -struct aspa_provider { - uint32_t as; - enum afi afi; -}; - /* * A single ASPA record */ @@ -367,7 +362,7 @@ struct aspa { char *sia; /* SIA signedObject */ char *ski; /* SKI */ uint32_t custasid; /* the customerASID */ - struct aspa_provider *providers; /* the providers */ + uint32_t *providers; /* the providers */ size_t providersz; /* number of providers */ time_t signtime; /* CMS signing-time attribute */ time_t notbefore; /* EE cert's Not Before */ @@ -382,7 +377,7 @@ struct aspa { struct vap { RB_ENTRY(vap) entry; uint32_t custasid; - struct aspa_provider *providers; + uint32_t *providers; size_t providersz; time_t expires; int talid; diff --git a/usr.sbin/rpki-client/output-bgpd.c b/usr.sbin/rpki-client/output-bgpd.c index 5709ec77fb3..1207f46d51b 100644 --- a/usr.sbin/rpki-client/output-bgpd.c +++ b/usr.sbin/rpki-client/output-bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: output-bgpd.c,v 1.27 2023/04/19 19:26:26 job Exp $ */ +/* $OpenBSD: output-bgpd.c,v 1.28 2023/06/26 18:39:53 job Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons * @@ -63,18 +63,8 @@ output_bgpd(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks, (long long)vap->expires) < 0) return -1; for (i = 0; i < vap->providersz; i++) { - if (fprintf(out, "%u", vap->providers[i].as) < 0) + if (fprintf(out, "%u", vap->providers[i]) < 0) return -1; - switch (vap->providers[i].afi) { - case AFI_IPV4: - if (fprintf(out, " inet") < 0) - return -1; - break; - case AFI_IPV6: - if (fprintf(out, " inet6") < 0) - return -1; - break; - } if (i + 1 < vap->providersz) if (fprintf(out, ", ") < 0) return -1; diff --git a/usr.sbin/rpki-client/output-json.c b/usr.sbin/rpki-client/output-json.c index dce33e631c5..ddb8b8cda2c 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.39 2023/06/05 14:19:13 claudio Exp $ */ +/* $OpenBSD: output-json.c,v 1.40 2023/06/26 18:39:53 job Exp $ */ /* * Copyright (c) 2019 Claudio Jeker * @@ -82,24 +82,18 @@ outputheader_json(struct stats *st) } static void -print_vap(struct vap *v, enum afi afi) +print_vap(struct vap *v) { size_t i; - int found = 0; json_do_object("aspa", 1); json_do_int("customer_asid", v->custasid); json_do_int("expires", v->expires); json_do_array("providers"); - for (i = 0; i < v->providersz; i++) { - if (v->providers[i].afi != 0 && v->providers[i].afi != afi) - continue; - found = 1; - json_do_int("provider", v->providers[i].as); - } - if (!found) - json_do_int("provider", 0); + for (i = 0; i < v->providersz; i++) + json_do_int("provider", v->providers[i]); + json_do_end(); } @@ -108,18 +102,9 @@ output_aspa(struct vap_tree *vaps) { struct vap *v; - json_do_object("provider_authorizations", 0); - - json_do_array("ipv4"); - RB_FOREACH(v, vap_tree, vaps) { - print_vap(v, AFI_IPV4); - } - json_do_end(); - - json_do_array("ipv6"); - RB_FOREACH(v, vap_tree, vaps) { - print_vap(v, AFI_IPV6); - } + json_do_array("aspas"); + RB_FOREACH(v, vap_tree, vaps) + print_vap(v); json_do_end(); } diff --git a/usr.sbin/rpki-client/print.c b/usr.sbin/rpki-client/print.c index 1b58bf20ab5..5221d29d21a 100644 --- a/usr.sbin/rpki-client/print.c +++ b/usr.sbin/rpki-client/print.c @@ -1,4 +1,4 @@ -/* $OpenBSD: print.c,v 1.40 2023/06/05 14:19:13 claudio Exp $ */ +/* $OpenBSD: print.c,v 1.41 2023/06/26 18:39:53 job Exp $ */ /* * Copyright (c) 2021 Claudio Jeker * Copyright (c) 2019 Kristaps Dzonsons @@ -613,59 +613,23 @@ rsc_print(const X509 *x, const struct rsc *p) } static void -aspa_provider(uint32_t as, enum afi afi) +aspa_provider(uint32_t as) { if (outformats & FORMAT_JSON) { json_do_object("aspa", 1); json_do_uint("asid", as); - if (afi == AFI_IPV4) - json_do_string("afi_limit", "ipv4"); - if (afi == AFI_IPV6) - json_do_string("afi_limit", "ipv6"); json_do_end(); } else { printf("AS: %u", as); - if (afi == AFI_IPV4) - printf(" (IPv4 only)"); - if (afi == AFI_IPV6) - printf(" (IPv6 only)"); printf("\n"); } } -static void -aspa_providers(const struct aspa *a) -{ - size_t i; - int hasv4 = 0, hasv6 = 0; - - for (i = 0; i < a->providersz; i++) { - if ((outformats & FORMAT_JSON) == 0 && i > 0) - printf("%26s", ""); - aspa_provider(a->providers[i].as, a->providers[i].afi); - - switch (a->providers[i].afi) { - case AFI_IPV4: - hasv4 = 1; - break; - case AFI_IPV6: - hasv6 = 1; - break; - default: - hasv4 = hasv6 = 1; - break; - } - } - - if (!hasv4) - aspa_provider(0, AFI_IPV4); - if (!hasv6) - aspa_provider(0, AFI_IPV6); -} - void aspa_print(const X509 *x, const struct aspa *p) { + size_t i; + if (outformats & FORMAT_JSON) { json_do_string("type", "aspa"); json_do_string("ski", pretty_key_id(p->ski)); @@ -697,7 +661,11 @@ aspa_print(const X509 *x, const struct aspa *p) printf("Provider set: "); } - aspa_providers(p); + for (i = 0; i < p->providersz; i++) { + if ((outformats & FORMAT_JSON) == 0 && i > 0) + printf("%26s", ""); + aspa_provider(p->providers[i]); + } if (outformats & FORMAT_JSON) json_do_end(); diff --git a/usr.sbin/rpki-client/rpki-client.8 b/usr.sbin/rpki-client/rpki-client.8 index 68e28a453ad..0644f33094b 100644 --- a/usr.sbin/rpki-client/rpki-client.8 +++ b/usr.sbin/rpki-client/rpki-client.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: rpki-client.8,v 1.96 2023/06/07 16:23:02 job Exp $ +.\" $OpenBSD: rpki-client.8,v 1.97 2023/06/26 18:39:53 job Exp $ .\" .\" Copyright (c) 2019 Kristaps Dzonsons .\" @@ -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: June 7 2023 $ +.Dd $Mdocdate: June 26 2023 $ .Dt RPKI-CLIENT 8 .Os .Sh NAME @@ -389,7 +389,7 @@ agreement regarding ARIN service restrictions. .Rs .%T A Profile for Autonomous System Provider Authorization (ASPA) .%U https://datatracker.ietf.org/doc/html/draft-ietf-sidrops-aspa-profile -.%D Jan, 2023 +.%D Jun, 2023 .Re .Pp .Rs -- 2.20.1