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

Reply via email to