Download raw body.
rpki-client: move most rfc 3779 parsing code
This diff moves most of the RFC 3779 extension unpacking into ip.c and
as.c and renames the two sbgp_* cert extension handler into cert_* for
consistency inside cert.c. Two static cert_*as*() helpers stay there.
The cert.c code is complex enough without them, and ip.c and as.c exist
for this reason. The sbgp_* prototypes in extern.h are already grouped
with the ip_* and as_* functions rather than the cert_* functions.
The bulk of the diff is a plain move of code I reworked when migrating
rpki-client to templated ASN.1. There is perhaps an argument that the
functions should remain close to each other due to their similarity.
I can't remember that this ever helped me.
I dislike how append_as() and append_ip() rely on the caller many
levels down to have allocated enough room, but that's for another
round of bikeshedding.
Index: as.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/as.c,v
diff -u -p -r1.18 as.c
--- as.c 9 Apr 2026 07:47:31 -0000 1.18
+++ as.c 29 Apr 2026 06:06:46 -0000
@@ -1,6 +1,7 @@
/* $OpenBSD: as.c,v 1.18 2026/04/09 07:47:31 tb Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -15,6 +16,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <assert.h>
#include <err.h>
#include <stdint.h>
#include <stdlib.h>
@@ -154,4 +156,180 @@ as_warn(const char *fn, const char *msg,
warnx("%s: corrupt cert", fn);
break;
}
+}
+
+/*
+ * Append an AS identifier structure to our list of results.
+ * Makes sure that the identifiers do not overlap or improperly inherit
+ * as defined by RFC 3779 section 3.3.
+ */
+static int
+append_as(const char *fn, struct cert_as *ases, size_t *num_ases,
+ const struct cert_as *as)
+{
+ if (!as_check_overlap(as, fn, ases, *num_ases, 0))
+ return 0;
+ ases[(*num_ases)++] = *as;
+ return 1;
+}
+
+/*
+ * Parse a range of AS identifiers as in 3.2.3.8.
+ * Returns zero on failure, non-zero on success.
+ */
+int
+sbgp_as_range(const char *fn, struct cert_as *ases, size_t *num_ases,
+ const ASRange *range)
+{
+ struct cert_as as;
+
+ memset(&as, 0, sizeof(struct cert_as));
+ as.type = CERT_AS_RANGE;
+
+ if (!as_id_parse(range->min, &as.range.min)) {
+ warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
+ "malformed AS identifier", fn);
+ return 0;
+ }
+
+ if (!as_id_parse(range->max, &as.range.max)) {
+ warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
+ "malformed AS identifier", fn);
+ return 0;
+ }
+
+ if (as.range.max == as.range.min) {
+ warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
+ "range is singular", fn);
+ return 0;
+ } else if (as.range.max < as.range.min) {
+ warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
+ "range is out of order", fn);
+ return 0;
+ }
+
+ return append_as(fn, ases, num_ases, &as);
+}
+
+/*
+ * Parse an entire 3.2.3.10 integer type.
+ */
+int
+sbgp_as_id(const char *fn, struct cert_as *ases, size_t *num_ases,
+ const ASN1_INTEGER *i)
+{
+ struct cert_as as;
+
+ memset(&as, 0, sizeof(struct cert_as));
+ as.type = CERT_AS_ID;
+
+ if (!as_id_parse(i, &as.id)) {
+ warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
+ "malformed AS identifier", fn);
+ return 0;
+ }
+ if (as.id == 0) {
+ warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
+ "AS identifier zero is reserved", fn);
+ return 0;
+ }
+
+ return append_as(fn, ases, num_ases, &as);
+}
+
+static int
+sbgp_as_inherit(const char *fn, struct cert_as *ases, size_t *num_ases)
+{
+ struct cert_as as;
+
+ memset(&as, 0, sizeof(struct cert_as));
+ as.type = CERT_AS_INHERIT;
+
+ return append_as(fn, ases, num_ases, &as);
+}
+
+int
+sbgp_parse_asids(const char *fn, const ASIdentifiers *asidentifiers,
+ struct cert_as **out_as, size_t *out_num_ases)
+{
+ const ASIdOrRanges *aors = NULL;
+ struct cert_as *as = NULL;
+ size_t num_ases = 0, num;
+ int i;
+
+ assert(*out_as == NULL && *out_num_ases == 0);
+
+ if (asidentifiers->rdi != NULL) {
+ warnx("%s: RFC 6487 section 4.8.11: autonomousSysIds: "
+ "should not have RDI values", fn);
+ goto out;
+ }
+
+ if (asidentifiers->asnum == NULL) {
+ warnx("%s: RFC 6487 section 4.8.11: autonomousSysIds: "
+ "no AS number resource set", fn);
+ goto out;
+ }
+
+ switch (asidentifiers->asnum->type) {
+ case ASIdentifierChoice_inherit:
+ num = 1;
+ break;
+ case ASIdentifierChoice_asIdsOrRanges:
+ aors = asidentifiers->asnum->u.asIdsOrRanges;
+ num = sk_ASIdOrRange_num(aors);
+ break;
+ default:
+ warnx("%s: RFC 3779 section 3.2.3.2: ASIdentifierChoice: "
+ "unknown type %d", fn, asidentifiers->asnum->type);
+ goto out;
+ }
+
+ if (num == 0) {
+ warnx("%s: RFC 6487 section 4.8.11: empty asIdsOrRanges", fn);
+ goto out;
+ }
+ if (num >= MAX_AS_SIZE) {
+ warnx("%s: too many AS number entries: limit %d",
+ fn, MAX_AS_SIZE);
+ goto out;
+ }
+ as = calloc(num, sizeof(struct cert_as));
+ if (as == NULL)
+ err(1, NULL);
+
+ if (aors == NULL) {
+ if (!sbgp_as_inherit(fn, as, &num_ases))
+ goto out;
+ }
+
+ for (i = 0; i < sk_ASIdOrRange_num(aors); i++) {
+ const ASIdOrRange *aor;
+
+ aor = sk_ASIdOrRange_value(aors, i);
+ switch (aor->type) {
+ case ASIdOrRange_id:
+ if (!sbgp_as_id(fn, as, &num_ases, aor->u.id))
+ goto out;
+ break;
+ case ASIdOrRange_range:
+ if (!sbgp_as_range(fn, as, &num_ases, aor->u.range))
+ goto out;
+ break;
+ default:
+ warnx("%s: RFC 3779 section 3.2.3.5: ASIdOrRange: "
+ "unknown type %d", fn, aor->type);
+ goto out;
+ }
+ }
+
+ *out_as = as;
+ *out_num_ases = num_ases;
+
+ return 1;
+
+ out:
+ free(as);
+
+ return 0;
}
Index: cert.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
diff -u -p -r1.232 cert.c
--- cert.c 7 Apr 2026 10:59:19 -0000 1.232
+++ cert.c 8 Apr 2026 06:08:51 -0000
@@ -1024,217 +1024,12 @@ cert_policies(const char *fn, struct cer
}
/*
- * Append an IP address structure to our list of results, ensuring there is
- * at most one inheritance marker per AFI and no overlapping ranges.
- */
-static int
-append_ip(const char *fn, struct cert_ip *ips, size_t *num_ips,
- const struct cert_ip *ip)
-{
- if (!ip_addr_check_overlap(ip, fn, ips, *num_ips, 0))
- return 0;
- ips[(*num_ips)++] = *ip;
- return 1;
-}
-
-/*
- * Construct a RFC 3779 2.2.3.8 range from its bit string.
- * Returns zero on failure, non-zero on success.
- */
-int
-sbgp_addr(const char *fn, struct cert_ip *ips, size_t *num_ips, enum afi afi,
- const ASN1_BIT_STRING *bs)
-{
- struct cert_ip ip;
-
- memset(&ip, 0, sizeof(struct cert_ip));
-
- ip.afi = afi;
- ip.type = CERT_IP_ADDR;
-
- if (!ip_addr_parse(bs, afi, fn, &ip.ip)) {
- warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
- "invalid IP address", fn);
- return 0;
- }
-
- if (!ip_cert_compose_ranges(&ip)) {
- warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
- "IP address range reversed", fn);
- return 0;
- }
-
- return append_ip(fn, ips, num_ips, &ip);
-}
-
-/*
- * Parse RFC 3779 2.2.3.9 range of addresses.
- * Returns zero on failure, non-zero on success.
- */
-int
-sbgp_addr_range(const char *fn, struct cert_ip *ips, size_t *num_ips,
- enum afi afi, const IPAddressRange *range)
-{
- struct cert_ip ip;
-
- memset(&ip, 0, sizeof(struct cert_ip));
-
- ip.afi = afi;
- ip.type = CERT_IP_RANGE;
-
- if (!ip_addr_parse(range->min, afi, fn, &ip.range.min)) {
- warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
- "invalid IP address", fn);
- return 0;
- }
-
- if (!ip_addr_parse(range->max, afi, fn, &ip.range.max)) {
- warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
- "invalid IP address", fn);
- return 0;
- }
-
- if (!ip_cert_compose_ranges(&ip)) {
- warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
- "IP address range reversed", fn);
- return 0;
- }
-
- return append_ip(fn, ips, num_ips, &ip);
-}
-
-static int
-sbgp_addr_inherit(const char *fn, struct cert_ip *ips, size_t *num_ips,
- enum afi afi)
-{
- struct cert_ip ip;
-
- memset(&ip, 0, sizeof(struct cert_ip));
-
- ip.afi = afi;
- ip.type = CERT_IP_INHERIT;
-
- return append_ip(fn, ips, num_ips, &ip);
-}
-
-int
-sbgp_parse_ipaddrblocks(const char *fn, const IPAddrBlocks *addrs,
- struct cert_ip **out_ips, size_t *out_num_ips)
-{
- const IPAddressFamily *af;
- const IPAddressOrRanges *aors;
- const IPAddressOrRange *aor;
- enum afi afi;
- struct cert_ip *ips = NULL;
- size_t num_ips = 0, num;
- int ipv4_seen = 0, ipv6_seen = 0;
- int i, j, addrsz;
-
- assert(*out_ips == NULL && *out_num_ips == 0);
-
- addrsz = sk_IPAddressFamily_num(addrs);
- if (addrsz != 1 && addrsz != 2) {
- warnx("%s: RFC 6487 section 4.8.10: unexpected number of "
- "ipAddrBlocks (got %d, expected 1 or 2)", fn, addrsz);
- goto out;
- }
-
- for (i = 0; i < addrsz; i++) {
- af = sk_IPAddressFamily_value(addrs, i);
-
- switch (af->ipAddressChoice->type) {
- case IPAddressChoice_inherit:
- aors = NULL;
- num = num_ips + 1;
- break;
- case IPAddressChoice_addressesOrRanges:
- aors = af->ipAddressChoice->u.addressesOrRanges;
- num = num_ips + sk_IPAddressOrRange_num(aors);
- break;
- default:
- warnx("%s: RFC 3779: IPAddressChoice: unknown type %d",
- fn, af->ipAddressChoice->type);
- goto out;
- }
- if (num == num_ips) {
- warnx("%s: RFC 6487 section 4.8.10: "
- "empty ipAddressesOrRanges", fn);
- goto out;
- }
-
- if (num >= MAX_IP_SIZE)
- goto out;
- ips = recallocarray(ips, num_ips, num, sizeof(struct cert_ip));
- if (ips == NULL)
- err(1, NULL);
-
- if (!ip_addr_afi_parse(fn, af->addressFamily, &afi)) {
- warnx("%s: RFC 3779: invalid AFI", fn);
- goto out;
- }
-
- switch (afi) {
- case AFI_IPV4:
- if (ipv4_seen++ > 0) {
- warnx("%s: RFC 6487 section 4.8.10: "
- "IPv4 appears twice", fn);
- goto out;
- }
- break;
- case AFI_IPV6:
- if (ipv6_seen++ > 0) {
- warnx("%s: RFC 6487 section 4.8.10: "
- "IPv6 appears twice", fn);
- goto out;
- }
- break;
- }
-
- if (aors == NULL) {
- if (!sbgp_addr_inherit(fn, ips, &num_ips, afi))
- goto out;
- continue;
- }
-
- for (j = 0; j < sk_IPAddressOrRange_num(aors); j++) {
- aor = sk_IPAddressOrRange_value(aors, j);
- switch (aor->type) {
- case IPAddressOrRange_addressPrefix:
- if (!sbgp_addr(fn, ips, &num_ips, afi,
- aor->u.addressPrefix))
- goto out;
- break;
- case IPAddressOrRange_addressRange:
- if (!sbgp_addr_range(fn, ips, &num_ips, afi,
- aor->u.addressRange))
- goto out;
- break;
- default:
- warnx("%s: RFC 3779: IPAddressOrRange: "
- "unknown type %d", fn, aor->type);
- goto out;
- }
- }
- }
-
- *out_ips = ips;
- *out_num_ips = num_ips;
-
- return 1;
-
- out:
- free(ips);
-
- return 0;
-}
-
-/*
* Parse an IP Resources X.509v3 extension, RFC 6487 4.8.10, with
* syntax documented in RFC 3779 starting in section 2.2.
* Returns zero on failure, non-zero on success.
*/
static int
-sbgp_ipaddrblocks(const char *fn, struct cert *cert, const X509_EXTENSION *ext)
+cert_ipaddrblocks(const char *fn, struct cert *cert, const X509_EXTENSION *ext)
{
IPAddrBlocks *addrs = NULL;
int rc = 0;
@@ -1266,96 +1061,6 @@ sbgp_ipaddrblocks(const char *fn, struct
return rc;
}
-/*
- * Append an AS identifier structure to our list of results.
- * Makes sure that the identifiers do not overlap or improperly inherit
- * as defined by RFC 3779 section 3.3.
- */
-static int
-append_as(const char *fn, struct cert_as *ases, size_t *num_ases,
- const struct cert_as *as)
-{
- if (!as_check_overlap(as, fn, ases, *num_ases, 0))
- return 0;
- ases[(*num_ases)++] = *as;
- return 1;
-}
-
-/*
- * Parse a range of AS identifiers as in 3.2.3.8.
- * Returns zero on failure, non-zero on success.
- */
-int
-sbgp_as_range(const char *fn, struct cert_as *ases, size_t *num_ases,
- const ASRange *range)
-{
- struct cert_as as;
-
- memset(&as, 0, sizeof(struct cert_as));
- as.type = CERT_AS_RANGE;
-
- if (!as_id_parse(range->min, &as.range.min)) {
- warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
- "malformed AS identifier", fn);
- return 0;
- }
-
- if (!as_id_parse(range->max, &as.range.max)) {
- warnx("%s: RFC 3779 section 3.2.3.8 (via RFC 1930): "
- "malformed AS identifier", fn);
- return 0;
- }
-
- if (as.range.max == as.range.min) {
- warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
- "range is singular", fn);
- return 0;
- } else if (as.range.max < as.range.min) {
- warnx("%s: RFC 3379 section 3.2.3.8: ASRange: "
- "range is out of order", fn);
- return 0;
- }
-
- return append_as(fn, ases, num_ases, &as);
-}
-
-/*
- * Parse an entire 3.2.3.10 integer type.
- */
-int
-sbgp_as_id(const char *fn, struct cert_as *ases, size_t *num_ases,
- const ASN1_INTEGER *i)
-{
- struct cert_as as;
-
- memset(&as, 0, sizeof(struct cert_as));
- as.type = CERT_AS_ID;
-
- if (!as_id_parse(i, &as.id)) {
- warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
- "malformed AS identifier", fn);
- return 0;
- }
- if (as.id == 0) {
- warnx("%s: RFC 3779 section 3.2.3.10 (via RFC 1930): "
- "AS identifier zero is reserved", fn);
- return 0;
- }
-
- return append_as(fn, ases, num_ases, &as);
-}
-
-static int
-sbgp_as_inherit(const char *fn, struct cert_as *ases, size_t *num_ases)
-{
- struct cert_as as;
-
- memset(&as, 0, sizeof(struct cert_as));
- as.type = CERT_AS_INHERIT;
-
- return append_as(fn, ases, num_ases, &as);
-}
-
static int
cert_as_inherit(const struct cert *cert)
{
@@ -1374,99 +1079,13 @@ cert_has_one_as(const struct cert *cert)
return cert->ases[0].type == CERT_AS_ID;
}
-int
-sbgp_parse_asids(const char *fn, const ASIdentifiers *asidentifiers,
- struct cert_as **out_as, size_t *out_num_ases)
-{
- const ASIdOrRanges *aors = NULL;
- struct cert_as *as = NULL;
- size_t num_ases = 0, num;
- int i;
-
- assert(*out_as == NULL && *out_num_ases == 0);
-
- if (asidentifiers->rdi != NULL) {
- warnx("%s: RFC 6487 section 4.8.11: autonomousSysIds: "
- "should not have RDI values", fn);
- goto out;
- }
-
- if (asidentifiers->asnum == NULL) {
- warnx("%s: RFC 6487 section 4.8.11: autonomousSysIds: "
- "no AS number resource set", fn);
- goto out;
- }
-
- switch (asidentifiers->asnum->type) {
- case ASIdentifierChoice_inherit:
- num = 1;
- break;
- case ASIdentifierChoice_asIdsOrRanges:
- aors = asidentifiers->asnum->u.asIdsOrRanges;
- num = sk_ASIdOrRange_num(aors);
- break;
- default:
- warnx("%s: RFC 3779 section 3.2.3.2: ASIdentifierChoice: "
- "unknown type %d", fn, asidentifiers->asnum->type);
- goto out;
- }
-
- if (num == 0) {
- warnx("%s: RFC 6487 section 4.8.11: empty asIdsOrRanges", fn);
- goto out;
- }
- if (num >= MAX_AS_SIZE) {
- warnx("%s: too many AS number entries: limit %d",
- fn, MAX_AS_SIZE);
- goto out;
- }
- as = calloc(num, sizeof(struct cert_as));
- if (as == NULL)
- err(1, NULL);
-
- if (aors == NULL) {
- if (!sbgp_as_inherit(fn, as, &num_ases))
- goto out;
- }
-
- for (i = 0; i < sk_ASIdOrRange_num(aors); i++) {
- const ASIdOrRange *aor;
-
- aor = sk_ASIdOrRange_value(aors, i);
- switch (aor->type) {
- case ASIdOrRange_id:
- if (!sbgp_as_id(fn, as, &num_ases, aor->u.id))
- goto out;
- break;
- case ASIdOrRange_range:
- if (!sbgp_as_range(fn, as, &num_ases, aor->u.range))
- goto out;
- break;
- default:
- warnx("%s: RFC 3779 section 3.2.3.5: ASIdOrRange: "
- "unknown type %d", fn, aor->type);
- goto out;
- }
- }
-
- *out_as = as;
- *out_num_ases = num_ases;
-
- return 1;
-
- out:
- free(as);
-
- return 0;
-}
-
/*
* Parse an AS Resources X.509v3 extension, RFC 6487 4.8.11, with
* syntax documented in RFC 3779 starting in section 3.2.
* Returns zero on failure, non-zero on success.
*/
static int
-sbgp_asids(const char *fn, struct cert *cert, const X509_EXTENSION *ext)
+cert_asids(const char *fn, struct cert *cert, const X509_EXTENSION *ext)
{
ASIdentifiers *asidentifiers = NULL;
int rc = 0;
@@ -1587,13 +1206,13 @@ cert_parse_extensions(const char *fn, st
case NID_sbgp_ipAddrBlock:
if (ip++ > 0)
goto dup;
- if (!sbgp_ipaddrblocks(fn, cert, ext))
+ if (!cert_ipaddrblocks(fn, cert, ext))
goto out;
break;
case NID_sbgp_autonomousSysNum:
if (as++ > 0)
goto dup;
- if (!sbgp_asids(fn, cert, ext))
+ if (!cert_asids(fn, cert, ext))
goto out;
break;
default:
Index: ip.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/ip.c,v
diff -u -p -r1.37 ip.c
--- ip.c 4 Dec 2025 06:11:44 -0000 1.37
+++ ip.c 29 Apr 2026 06:06:27 -0000
@@ -1,6 +1,7 @@
/* $OpenBSD: ip.c,v 1.37 2025/12/04 06:11:44 tb Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
+ * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -18,6 +19,7 @@
#include <sys/socket.h>
#include <arpa/inet.h>
+#include <assert.h>
#include <err.h>
#include <stdlib.h>
#include <string.h>
@@ -366,4 +368,209 @@ ip_warn(const char *fn, const char *msg,
warnx("%s: corrupt cert", fn);
break;
}
+}
+
+/*
+ * Append an IP address structure to our list of results, ensuring there is
+ * at most one inheritance marker per AFI and no overlapping ranges.
+ */
+static int
+append_ip(const char *fn, struct cert_ip *ips, size_t *num_ips,
+ const struct cert_ip *ip)
+{
+ if (!ip_addr_check_overlap(ip, fn, ips, *num_ips, 0))
+ return 0;
+ ips[(*num_ips)++] = *ip;
+ return 1;
+}
+
+/*
+ * Construct a RFC 3779 2.2.3.8 range from its bit string.
+ * Returns zero on failure, non-zero on success.
+ */
+int
+sbgp_addr(const char *fn, struct cert_ip *ips, size_t *num_ips, enum afi afi,
+ const ASN1_BIT_STRING *bs)
+{
+ struct cert_ip ip;
+
+ memset(&ip, 0, sizeof(struct cert_ip));
+
+ ip.afi = afi;
+ ip.type = CERT_IP_ADDR;
+
+ if (!ip_addr_parse(bs, afi, fn, &ip.ip)) {
+ warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
+ "invalid IP address", fn);
+ return 0;
+ }
+
+ if (!ip_cert_compose_ranges(&ip)) {
+ warnx("%s: RFC 3779 section 2.2.3.8: IPAddress: "
+ "IP address range reversed", fn);
+ return 0;
+ }
+
+ return append_ip(fn, ips, num_ips, &ip);
+}
+
+/*
+ * Parse RFC 3779 2.2.3.9 range of addresses.
+ * Returns zero on failure, non-zero on success.
+ */
+int
+sbgp_addr_range(const char *fn, struct cert_ip *ips, size_t *num_ips,
+ enum afi afi, const IPAddressRange *range)
+{
+ struct cert_ip ip;
+
+ memset(&ip, 0, sizeof(struct cert_ip));
+
+ ip.afi = afi;
+ ip.type = CERT_IP_RANGE;
+
+ if (!ip_addr_parse(range->min, afi, fn, &ip.range.min)) {
+ warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
+ "invalid IP address", fn);
+ return 0;
+ }
+
+ if (!ip_addr_parse(range->max, afi, fn, &ip.range.max)) {
+ warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
+ "invalid IP address", fn);
+ return 0;
+ }
+
+ if (!ip_cert_compose_ranges(&ip)) {
+ warnx("%s: RFC 3779 section 2.2.3.9: IPAddressRange: "
+ "IP address range reversed", fn);
+ return 0;
+ }
+
+ return append_ip(fn, ips, num_ips, &ip);
+}
+
+static int
+sbgp_addr_inherit(const char *fn, struct cert_ip *ips, size_t *num_ips,
+ enum afi afi)
+{
+ struct cert_ip ip;
+
+ memset(&ip, 0, sizeof(struct cert_ip));
+
+ ip.afi = afi;
+ ip.type = CERT_IP_INHERIT;
+
+ return append_ip(fn, ips, num_ips, &ip);
+}
+
+int
+sbgp_parse_ipaddrblocks(const char *fn, const IPAddrBlocks *addrs,
+ struct cert_ip **out_ips, size_t *out_num_ips)
+{
+ const IPAddressFamily *af;
+ const IPAddressOrRanges *aors;
+ const IPAddressOrRange *aor;
+ enum afi afi;
+ struct cert_ip *ips = NULL;
+ size_t num_ips = 0, num;
+ int ipv4_seen = 0, ipv6_seen = 0;
+ int i, j, addrsz;
+
+ assert(*out_ips == NULL && *out_num_ips == 0);
+
+ addrsz = sk_IPAddressFamily_num(addrs);
+ if (addrsz != 1 && addrsz != 2) {
+ warnx("%s: RFC 6487 section 4.8.10: unexpected number of "
+ "ipAddrBlocks (got %d, expected 1 or 2)", fn, addrsz);
+ goto out;
+ }
+
+ for (i = 0; i < addrsz; i++) {
+ af = sk_IPAddressFamily_value(addrs, i);
+
+ switch (af->ipAddressChoice->type) {
+ case IPAddressChoice_inherit:
+ aors = NULL;
+ num = num_ips + 1;
+ break;
+ case IPAddressChoice_addressesOrRanges:
+ aors = af->ipAddressChoice->u.addressesOrRanges;
+ num = num_ips + sk_IPAddressOrRange_num(aors);
+ break;
+ default:
+ warnx("%s: RFC 3779: IPAddressChoice: unknown type %d",
+ fn, af->ipAddressChoice->type);
+ goto out;
+ }
+ if (num == num_ips) {
+ warnx("%s: RFC 6487 section 4.8.10: "
+ "empty ipAddressesOrRanges", fn);
+ goto out;
+ }
+
+ if (num >= MAX_IP_SIZE)
+ goto out;
+ ips = recallocarray(ips, num_ips, num, sizeof(struct cert_ip));
+ if (ips == NULL)
+ err(1, NULL);
+
+ if (!ip_addr_afi_parse(fn, af->addressFamily, &afi)) {
+ warnx("%s: RFC 3779: invalid AFI", fn);
+ goto out;
+ }
+
+ switch (afi) {
+ case AFI_IPV4:
+ if (ipv4_seen++ > 0) {
+ warnx("%s: RFC 6487 section 4.8.10: "
+ "IPv4 appears twice", fn);
+ goto out;
+ }
+ break;
+ case AFI_IPV6:
+ if (ipv6_seen++ > 0) {
+ warnx("%s: RFC 6487 section 4.8.10: "
+ "IPv6 appears twice", fn);
+ goto out;
+ }
+ break;
+ }
+
+ if (aors == NULL) {
+ if (!sbgp_addr_inherit(fn, ips, &num_ips, afi))
+ goto out;
+ continue;
+ }
+
+ for (j = 0; j < sk_IPAddressOrRange_num(aors); j++) {
+ aor = sk_IPAddressOrRange_value(aors, j);
+ switch (aor->type) {
+ case IPAddressOrRange_addressPrefix:
+ if (!sbgp_addr(fn, ips, &num_ips, afi,
+ aor->u.addressPrefix))
+ goto out;
+ break;
+ case IPAddressOrRange_addressRange:
+ if (!sbgp_addr_range(fn, ips, &num_ips, afi,
+ aor->u.addressRange))
+ goto out;
+ break;
+ default:
+ warnx("%s: RFC 3779: IPAddressOrRange: "
+ "unknown type %d", fn, aor->type);
+ goto out;
+ }
+ }
+ }
+
+ *out_ips = ips;
+ *out_num_ips = num_ips;
+
+ return 1;
+
+ out:
+ free(ips);
+
+ return 0;
}
rpki-client: move most rfc 3779 parsing code