Instead of manually unpacking the SIA extension with super low-level
ASN.1 fiddling, we can let the templated ASN.1 in libcrypto do this work
for us, which makes the code quite a bit simpler. This resolves one
FIXME and removes one use of the magic ASN1_frame().

I kept the current split of the functions to avoid noise and make the
diff easier to review. I'm going to undo this split in a follow-up.

The relevant structs and typedefs are in x509/x509v3.h and the ASN.1
templates are in x509/x509_info.c if you want to take a look at that.

The main point is the X509V3_EXT_d2i() in sbgp_sia(), which deserializes
the extension based on its OID, which was checked in cert_parse_pre().
We (ab)use the AUTHORITY_INFO_ACCESS type since there is unfortunately
no SUBJECT_INFO_ACCESS type (the extensions have the same syntax, see
RFC 5280, 4.2.2). This is documented in AUTHORITY_INFO_ACCESS_new(3).
A typedef might be appropriate here.

AUTHORITY_INFO_ACCESS is a STACK_OF(ACCESS_DESCRIPTION), the unpacking
of which is done in sbgp_sia_resource().

ACCESS_DESCRIPTION has an oid (ASN1_OBJECT) called method and a
GENERAL_NAME called location. All three resources we currently care
about are of the URI type, the new GEN_URI check makes sure of that
(the discarded ptag argument of ASN1_frame() should have been checked
to be GEN_URI).

Overall, I think the resulting code is a lot easier to follow and more
correct.

Index: cert.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.62
diff -u -p -r1.62 cert.c
--- cert.c      5 Apr 2022 03:56:20 -0000       1.62
+++ cert.c      5 Apr 2022 04:54:18 -0000
@@ -214,63 +214,45 @@ sbgp_sia_resource_carepo(struct parse *p
  * Returns zero on failure, non-zero on success.
  */
 static int
-sbgp_sia_resource_entry(struct parse *p,
-       const unsigned char *d, size_t dsz)
+sbgp_sia_resource_entry(struct parse *p, ACCESS_DESCRIPTION *ad)
 {
-       ASN1_SEQUENCE_ANY       *seq;
        ASN1_OBJECT             *oid;
-       const ASN1_TYPE         *t;
-       int                      rc = 0, ptag;
-       long                     plen;
+       ASN1_IA5STRING          *uri = NULL;
+       int                      rc = 0;
 
-       if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
-               cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
-                   "failed ASN.1 sequence parse", p->fn);
-               goto out;
-       }
-       if (sk_ASN1_TYPE_num(seq) != 2) {
-               warnx("%s: RFC 6487 section 4.8.8: SIA: "
-                   "want 2 elements, have %d",
-                   p->fn, sk_ASN1_TYPE_num(seq));
-               goto out;
-       }
+       if (ad->location->type == GEN_URI)
+               uri = ad->location->d.uniformResourceIdentifier;
 
-       /* Composed of an OID and its continuation. */
+       oid = ad->method;
 
-       t = sk_ASN1_TYPE_value(seq, 0);
-       if (t->type != V_ASN1_OBJECT) {
-               warnx("%s: RFC 6487 section 4.8.8: SIA: "
-                   "want ASN.1 object, have %s (NID %d)",
-                   p->fn, ASN1_tag2str(t->type), t->type);
-               goto out;
-       }
-       oid = t->value.object;
-
-       t = sk_ASN1_TYPE_value(seq, 1);
-       if (t->type != V_ASN1_OTHER) {
-               warnx("%s: RFC 6487 section 4.8.8: SIA: "
-                   "want ASN.1 external, have %s (NID %d)",
-                   p->fn, ASN1_tag2str(t->type), t->type);
-               goto out;
+       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 resourceNnotify "
+                           "without URI", p->fn);
+                       goto out;
+               }
+               if (!sbgp_sia_resource_notify(p, uri->data, uri->length))
+                       goto out;
        }
 
-       /* FIXME: there must be a way to do this without ASN1_frame. */
-
-       d = t->value.asn1_string->data;
-       dsz = t->value.asn1_string->length;
-       if (!ASN1_frame(p->fn, dsz, &d, &plen, &ptag))
-               goto out;
-
-       if (OBJ_cmp(oid, carepo_oid) == 0)
-               rc = sbgp_sia_resource_carepo(p, d, plen);
-       else if (OBJ_cmp(oid, manifest_oid) == 0)
-               rc = sbgp_sia_resource_mft(p, d, plen);
-       else if (OBJ_cmp(oid, notify_oid) == 0)
-               rc = sbgp_sia_resource_notify(p, d, plen);
-       else
-               rc = 1; /* silently ignore */
-out:
-       sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
+       rc = 1;
+ out:
        return rc;
 }
 
@@ -279,29 +261,14 @@ out:
  * Returns zero on failure, non-zero on success.
  */
 static int
-sbgp_sia_resource(struct parse *p, const unsigned char *d, size_t dsz)
+sbgp_sia_resource(struct parse *p, AUTHORITY_INFO_ACCESS *sia)
 {
-       ASN1_SEQUENCE_ANY       *seq;
-       const ASN1_TYPE         *t;
-       int                      rc = 0, i;
+       ACCESS_DESCRIPTION      *ad;
+       int                      i, rc = 0;
 
-       if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
-               cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
-                   "failed ASN.1 sequence parse", p->fn);
-               goto out;
-       }
-
-       for (i = 0; i < sk_ASN1_TYPE_num(seq); i++) {
-               t = sk_ASN1_TYPE_value(seq, i);
-               if (t->type != V_ASN1_SEQUENCE) {
-                       warnx("%s: RFC 6487 section 4.8.8: SIA: "
-                           "want ASN.1 sequence, have %s (NID %d)",
-                           p->fn, ASN1_tag2str(t->type), t->type);
-                       goto out;
-               }
-               d = t->value.asn1_string->data;
-               dsz = t->value.asn1_string->length;
-               if (!sbgp_sia_resource_entry(p, d, dsz))
+       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;
        }
 
@@ -317,9 +284,9 @@ sbgp_sia_resource(struct parse *p, const
                    p->fn);
                goto out;
        }
+
        rc = 1;
-out:
-       sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
+ out:
        return rc;
 }
 
@@ -330,11 +297,8 @@ out:
 static int
 sbgp_sia(struct parse *p, X509_EXTENSION *ext)
 {
-       unsigned char           *sv = NULL;
-       const unsigned char     *d;
-       ASN1_SEQUENCE_ANY       *seq = NULL;
-       const ASN1_TYPE         *t;
-       int                      dsz, rc = 0;
+       AUTHORITY_INFO_ACCESS   *sia = NULL;
+       int                      rc = 0;
 
        if (X509_EXTENSION_get_critical(ext)) {
                warnx("%s: RFC 6487 section 4.8.8: SIA: "
@@ -342,57 +306,17 @@ sbgp_sia(struct parse *p, X509_EXTENSION
                goto out;
        }
 
-       if ((dsz = i2d_X509_EXTENSION(ext, &sv)) < 0) {
+       if ((sia = X509V3_EXT_d2i(ext)) == NULL) {
                cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
                    "failed extension parse", p->fn);
                goto out;
        }
-       d = sv;
-
-       if ((seq = d2i_ASN1_SEQUENCE_ANY(NULL, &d, dsz)) == NULL) {
-               cryptowarnx("%s: RFC 6487 section 4.8.8: SIA: "
-                   "failed ASN.1 sequence parse", p->fn);
-               goto out;
-       }
-       if (sk_ASN1_TYPE_num(seq) != 2) {
-               warnx("%s: RFC 6487 section 4.8.8: SIA: "
-                   "want 2 elements, have %d", p->fn,
-                   sk_ASN1_TYPE_num(seq));
-               goto out;
-       }
-
-       t = sk_ASN1_TYPE_value(seq, 0);
-       if (t->type != V_ASN1_OBJECT) {
-               warnx("%s: RFC 6487 section 4.8.8: SIA: "
-                   "want ASN.1 object, have %s (NID %d)",
-                   p->fn, ASN1_tag2str(t->type), t->type);
-               goto out;
-       }
-       if (OBJ_obj2nid(t->value.object) != NID_sinfo_access) {
-               warnx("%s: RFC 6487 section 4.8.8: SIA: "
-                   "incorrect OID, have %s (NID %d)", p->fn,
-                   ASN1_tag2str(OBJ_obj2nid(t->value.object)),
-                   OBJ_obj2nid(t->value.object));
-               goto out;
-       }
-
-       t = sk_ASN1_TYPE_value(seq, 1);
-       if (t->type != V_ASN1_OCTET_STRING) {
-               warnx("%s: RFC 6487 section 4.8.8: SIA: "
-                   "want ASN.1 octet string, have %s (NID %d)",
-                   p->fn, ASN1_tag2str(t->type), t->type);
-               goto out;
-       }
-
-       d = t->value.octet_string->data;
-       dsz = t->value.octet_string->length;
-       if (!sbgp_sia_resource(p, d, dsz))
+       if (!sbgp_sia_resource(p, sia))
                goto out;
 
        rc = 1;
-out:
-       sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
-       free(sv);
+ out:
+       AUTHORITY_INFO_ACCESS_free(sia);
        return rc;
 }
 

Reply via email to