[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-tech
Subject:    rpki-client: make ASPA AFI-agnostic
From:       Job Snijders <job () openbsd ! org>
Date:       2023-06-07 12:21:23
Message-ID: ZIB2Q5y_-O1EZXhH () anton ! sobornost ! net
[Download RAW message or body]

Dear all,

To simplify the concept of RPKI ASPAs, the sidrops@ group came to
consensus on removing the notion of 'afiLimit'. This means that going
forward, ASPA will be AFI-agnostic.

Advantages to operators are that by creating just one ASPA they'll be
prepared for a IPv4+IPv6 dual-stack future (no need to update the ASPA
when IPv6 BGP sessions are added at a later point in time), and for BGP
implementers the cachability of the AS_PATH attribute is restored to its
former glory.

New ASPA profile definition is pending review here: https://github.com/QratorLabs/ASPA/pull/15/files

A test object reachable via RIPE NCC TAL is available here:
rsync://chloe.sobornost.net/rpki/RIPE-nljobsnijders/5m80fwYws_3FiFD7JiQjAqZ1RYQ.asa

Feedback?

Kind regards,

Job

Index: aspa.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/aspa.c,v
retrieving revision 1.18
diff -u -p -r1.18 aspa.c
--- aspa.c	7 Jun 2023 10:46:34 -0000	1.18
+++ aspa.c	7 Jun 2023 12:15:08 -0000
@@ -47,32 +47,15 @@ extern ASN1_OBJECT	*aspa_oid;
  */
 
 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(ASProviderAttes
  * 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, co
 		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 
 		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, 
 	 */
 	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++;
 	}
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.184
diff -u -p -r1.184 extern.h
--- extern.h	7 Jun 2023 10:46:34 -0000	1.184
+++ extern.h	7 Jun 2023 12:15:09 -0000
@@ -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;
Index: output-bgpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/output-bgpd.c,v
retrieving revision 1.27
diff -u -p -r1.27 output-bgpd.c
--- output-bgpd.c	19 Apr 2023 19:26:26 -0000	1.27
+++ output-bgpd.c	7 Jun 2023 12:15:09 -0000
@@ -63,18 +63,8 @@ output_bgpd(FILE *out, struct vrp_tree *
 		    (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;
Index: output-json.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/output-json.c,v
retrieving revision 1.39
diff -u -p -r1.39 output-json.c
--- output-json.c	5 Jun 2023 14:19:13 -0000	1.39
+++ output-json.c	7 Jun 2023 12:15:09 -0000
@@ -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("provider_authorizations");
+	RB_FOREACH(v, vap_tree, vaps)
+		print_vap(v);
 	json_do_end();
 }
 
Index: print.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/print.c,v
retrieving revision 1.40
diff -u -p -r1.40 print.c
--- print.c	5 Jun 2023 14:19:13 -0000	1.40
+++ print.c	7 Jun 2023 12:15:09 -0000
@@ -613,59 +613,23 @@ rsc_print(const X509 *x, const struct rs
 }
 
 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 a
 		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();

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic