Decode and validate ASPA objects following the v1 syntax
authorjob <job@openbsd.org>
Mon, 26 Jun 2023 18:39:53 +0000 (18:39 +0000)
committerjob <job@openbsd.org>
Mon, 26 Jun 2023 18:39:53 +0000 (18:39 +0000)
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
usr.sbin/rpki-client/extern.h
usr.sbin/rpki-client/output-bgpd.c
usr.sbin/rpki-client/output-json.c
usr.sbin/rpki-client/print.c
usr.sbin/rpki-client/rpki-client.8

index 1fdd3cb..07448fa 100644 (file)
@@ -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 <job@fastly.com>
  * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
@@ -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++;
        }
index abc945c..142442c 100644 (file)
@@ -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 <kristaps@bsd.lv>
  *
@@ -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 5709ec7..1207f46 100644 (file)
@@ -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 <kristaps@bsd.lv>
  *
@@ -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;
index dce33e6..ddb8b8c 100644 (file)
@@ -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 <claudio@openbsd.org>
  *
@@ -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();
 }
 
index 1b58bf2..5221d29 100644 (file)
@@ -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 <claudio@openbsd.org>
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -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();
index 68e28a4..0644f33 100644 (file)
@@ -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 <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: 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