For some reason libcrypto doesn't check this part of RFC 5280, 4.2:
A certificate MUST NOT include more than one instance of a particular
extension.

With the badCertSIA2x.cer from Ties's test artefacts, I get this warning:

rpki-client: badCertSIA2x.cer: RFC 5280 section 4.2: duplicate 
subjectInfoAccess extension

https://github.com/ties/rpki-commons-object-scan/tree/main/app/src/test/resources/bbn-conformance/root

The diff below is straightforward. It does not help EE certs. That
could be done similarly.

Index: cert.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.109
diff -u -p -r1.109 cert.c
--- cert.c      20 Jun 2023 12:28:08 -0000      1.109
+++ cert.c      20 Jun 2023 18:46:22 -0000
@@ -648,7 +648,6 @@ cert_parse_pre(const char *fn, const uns
 {
        const unsigned char     *oder;
        int                      extsz;
-       int                      sia_present = 0;
        size_t                   i;
        X509                    *x = NULL;
        X509_EXTENSION          *ext = NULL;
@@ -658,7 +657,10 @@ cert_parse_pre(const char *fn, const uns
        ASN1_OBJECT             *obj;
        EVP_PKEY                *pkey;
        struct parse             p;
-       int                      nid;
+       int                      nid, ip, as, sia, cp, crldp, aia, aki, ski,
+                                eku, bc, ku;
+
+       nid = ip = as = sia = cp = crldp = aia = aki = ski = eku = bc = ku = 0;
 
        /* just fail for empty buffers, the warning was printed elsewhere */
        if (der == NULL)
@@ -721,38 +723,58 @@ cert_parse_pre(const char *fn, const uns
                obj = X509_EXTENSION_get_object(ext);
                assert(obj != NULL);
 
-               switch (OBJ_obj2nid(obj)) {
+               switch ((nid = OBJ_obj2nid(obj))) {
                case NID_sbgp_ipAddrBlock:
+                       if (ip++ >= 1)
+                               goto dup;
                        if (!sbgp_ipaddrblk(&p, ext))
                                goto out;
                        break;
                case NID_sbgp_autonomousSysNum:
+                       if (as++ > 0)
+                               goto dup;
                        if (!sbgp_assysnum(&p, ext))
                                goto out;
                        break;
                case NID_sinfo_access:
-                       sia_present = 1;
+                       if (sia++ > 0)
+                               goto dup;
                        if (!sbgp_sia(&p, ext))
                                goto out;
                        break;
                case NID_certificate_policies:
+                       if (cp++ > 0)
+                               goto dup;
                        if (!certificate_policies(&p, ext))
                                goto out;
                        break;
                case NID_crl_distribution_points:
-                       /* ignored here, handled later */
+                       if (crldp++ > 0)
+                               goto dup;
                        break;
                case NID_info_access:
+                       if (aia++ > 0)
+                               goto dup;
                        break;
                case NID_authority_key_identifier:
+                       if (aki++ > 0)
+                               goto dup;
                        break;
                case NID_subject_key_identifier:
+                       if (ski++ > 0)
+                               goto dup;
                        break;
                case NID_ext_key_usage:
+                       if (eku++ > 0)
+                               goto dup;
                        break;
                case NID_basic_constraints:
+                       if (bc++ > 0)
+                               goto dup;
                        break;
                case NID_key_usage:
+                       if (ku++ > 0)
+                               goto dup;
                        break;
                default:
                        /* unexpected extensions warrant investigation */
@@ -831,7 +853,7 @@ cert_parse_pre(const char *fn, const uns
                                goto out;
                        }
                }
-               if (sia_present) {
+               if (sia) {
                        warnx("%s: unexpected SIA extension in BGPsec cert",
                            p.fn);
                        goto out;
@@ -850,7 +872,10 @@ cert_parse_pre(const char *fn, const uns
        p.res->x509 = x;
        return p.res;
 
-out:
+ dup:
+       warnx("%s: RFC 5280 section 4.2: duplicate %s extension", fn,
+           OBJ_nid2sn(nid));
+ out:
        cert_free(p.res);
        X509_free(x);
        return NULL;

Reply via email to