This should be the last step. It inlines sbgp_sia_resource_entry() into sbgp_sia() and dedups the sbgp_sia_resource_{notify,mft,carepo}() using a new sbgp_sia_location(). Move the GEN_URI check to sbgp_sia_location() since that seems cleaner.
Index: cert.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v retrieving revision 1.65 diff -u -p -r1.65 cert.c --- cert.c 11 Apr 2022 08:28:54 -0000 1.65 +++ cert.c 11 Apr 2022 09:27:53 -0000 @@ -125,132 +125,40 @@ sbgp_addr(struct parse *p, } /* - * Parse the SIA notify URL, 4.8.8.1. - * Returns zero on failure, non-zero on success. + * Extract and validate a SIA accessLocation, RFC 6487, 4.8.8 and RFC 8192, 3.2. + * Returns 0 on failure and 1 on success. */ static int -sbgp_sia_resource_notify(struct parse *p, const char *d, size_t dsz) +sbgp_sia_location(const char *fn, const char *descr, const char *proto, + GENERAL_NAME *location, char **out) { - if (p->res->notify != NULL) { - warnx("%s: RFC 6487 section 4.8.8: SIA: " - "Notify location already specified", p->fn); - return 0; - } - - /* Make sure it's a https:// address. */ - if (!valid_uri(d, dsz, "https://")) { - warnx("%s: RFC 8182 section 3.2: bad Notify URI", p->fn); - return 0; - } + ASN1_IA5STRING *uri; - if ((p->res->notify = strndup(d, dsz)) == NULL) - err(1, NULL); - - return 1; -} - -/* - * Parse the SIA manifest, 4.8.8.1. - * Returns zero on failure, non-zero on success. - */ -static int -sbgp_sia_resource_mft(struct parse *p, const char *d, size_t dsz) -{ - if (p->res->mft != NULL) { - warnx("%s: RFC 6487 section 4.8.8: SIA: " - "MFT location already specified", p->fn); + if (*out != NULL) { + warnx("%s: RFC 6487 section 4.8.8: SIA: %s already specified", + fn, descr); return 0; } - /* Make sure it's an rsync address. */ - if (!valid_uri(d, dsz, "rsync://")) { - warnx("%s: RFC 6487 section 4.8.8: bad MFT location", p->fn); + if (location->type != GEN_URI) { + warnx("%s: RFC 6487 section 4.8.8: SIA: %s not URI", fn, descr); return 0; } - if ((p->res->mft = strndup(d, dsz)) == NULL) - err(1, NULL); + uri = location->d.uniformResourceIdentifier; - return 1; -} - -/* - * Parse the SIA manifest, 4.8.8.1. - * Returns zero on failure, non-zero on success. - */ -static int -sbgp_sia_resource_carepo(struct parse *p, const char *d, size_t dsz) -{ - if (p->res->repo != NULL) { - warnx("%s: RFC 6487 section 4.8.8: SIA: " - "CA repository already specified", p->fn); + if (!valid_uri(uri->data, uri->length, proto)) { + warnx("%s: RFC 6487 section 4.8.8: bad %s location", fn, descr); return 0; } - /* Make sure it's an rsync:// address. */ - if (!valid_uri(d, dsz, "rsync://")) { - warnx("%s: RFC 6487 section 4.8.8: bad CA repository URI", - p->fn); - return 0; - } - - if ((p->res->repo = strndup(d, dsz)) == NULL) + if ((*out = strndup(uri->data, uri->length)) == NULL) err(1, NULL); return 1; } /* - * Parse the SIA entries, 4.8.8.1. - * There may be multiple different resources at this location, so throw - * out all but the matching resource type. Currently only two entries - * are of interest: rpkiManifest and rpkiNotify. - * Returns zero on failure, non-zero on success. - */ -static int -sbgp_sia_resource_entry(struct parse *p, ACCESS_DESCRIPTION *ad) -{ - ASN1_OBJECT *oid; - ASN1_IA5STRING *uri = NULL; - int rc = 0; - - if (ad->location->type == GEN_URI) - uri = ad->location->d.uniformResourceIdentifier; - - oid = ad->method; - - if (OBJ_cmp(oid, carepo_oid) == 0) { - if (uri == NULL) { - warnx("%s: RFC 6487: 4.8.8.1 caRepository without URI", - p->fn); - goto out; - } - if (!sbgp_sia_resource_carepo(p, uri->data, uri->length)) - goto out; - } else if (OBJ_cmp(oid, manifest_oid) == 0) { - if (uri == NULL) { - warnx("%s: RFC 6487: 4.8.8 SIA manifest without URI", - p->fn); - goto out; - } - if (!sbgp_sia_resource_mft(p, uri->data, uri->length)) - goto out; - } else if (OBJ_cmp(oid, notify_oid) == 0) { - if (uri == NULL) { - warnx("%s: RFC 6487: 4.8.8 SIA resourceNotify " - "without URI", p->fn); - goto out; - } - if (!sbgp_sia_resource_notify(p, uri->data, uri->length)) - goto out; - } - - rc = 1; - out: - return rc; -} - -/* * Parse "Subject Information Access" extension, RFC 6487 4.8.8. * Returns zero on failure, non-zero on success. */ @@ -259,6 +167,7 @@ sbgp_sia(struct parse *p, X509_EXTENSION { AUTHORITY_INFO_ACCESS *sia = NULL; ACCESS_DESCRIPTION *ad; + ASN1_OBJECT *oid; int i, rc = 0; if (X509_EXTENSION_get_critical(ext)) { @@ -275,8 +184,22 @@ sbgp_sia(struct parse *p, X509_EXTENSION for (i = 0; i < sk_ACCESS_DESCRIPTION_num(sia); i++) { ad = sk_ACCESS_DESCRIPTION_value(sia, i); - if (!sbgp_sia_resource_entry(p, ad)) - goto out; + + oid = ad->method; + + if (OBJ_cmp(oid, carepo_oid) == 0) { + if (!sbgp_sia_location(p->fn, "caRepository", + "rsync://", ad->location, &p->res->repo)) + goto out; + } else if (OBJ_cmp(oid, manifest_oid) == 0) { + if (!sbgp_sia_location(p->fn, "rpkiManifest", + "rsync://", ad->location, &p->res->mft)) + goto out; + } else if (OBJ_cmp(oid, notify_oid) == 0) { + if (!sbgp_sia_location(p->fn, "rpkiNotify", + "https://", ad->location, &p->res->notify)) + goto out; + } } if (p->res->mft == NULL || p->res->repo == NULL) {