On Fri, Apr 01, 2022 at 06:52:48PM +0200, Claudio Jeker wrote:
> On Fri, Apr 01, 2022 at 06:31:43PM +0200, Theo Buehler wrote:
> > On Fri, Apr 01, 2022 at 05:01:00PM +0200, Claudio Jeker wrote:
> > > cert_parse_inner() now only uses the ta flag to change behaviour of
> > > loading the various x509 extensions (AKI, SKI, AIA und CRL DP).
> > > 
> > > This diff changes these functions to work always. Make AKI, AIA and CRL DP
> > > optional and have the code calling those functions check if they must have
> > > the extension. I modelled the functions after x509_get_expire() so they
> > > return 0 on failure and 1 on success.
> > 
> > This looks pretty good.
> > 
> > There is a certain asymmetry with the SKI handling that confused me a
> > bit. At first, the strcmp(p->aki, p->ski) in ta_parse() and cert_parse()
> > looked like potential NULL derefs since it looks as if p->ski isn't
> > checked.
> > 
> > The check for p.res->ski != NULL at the end of cert_parse_inner() is no
> > longer necessary since x509_get_ski() would have failed.  Strictly
> > speaking, the ...->ski == NULL tests in {gbr,mft,roa}_parse() are also
> > no longer needed.
> > 
> > I would probably prefer to make x509_get_ski() behave the same way as
> > the AKI, AIA, CRL getters and add a p->ski != NULL check to ta_parse()
> > and cert_parse().
> 
> I think you're right, it may be better to behave the same for all of these
> extensions.
>  
> > >   if (p->aia == NULL) {
> > > -         warnx("%s: RFC 6487 section 8.4.7: "
> > > -             "non-trust anchor missing AIA", fn);
> > > +         warnx("%s: RFC 6487 section 8.4.7: AIA: extension missing", fn);
> > 
> > The warnings in this function aren't super consistent. We can clean this
> > up in a later pass.
> 
> I think this is a general concern for all of rpki-client. I switched the
> text because it is shorter :) Also it was the warning that would have been
> printed first.
> 
> > > @@ -360,7 +360,11 @@ proc_parser_mft_pre(char *file, const un
> > >  
> > >   a = valid_ski_aki(file, &auths, mft->ski, mft->aki);
> > >   /* load CRL by hand, since it is referenced by the MFT itself */
> > > - c = x509_get_crl(x509, file);
> > > + if (!x509_get_crl(x509, file, &c) || c == NULL) {
> > 
> > The c == NULL case now fails silently. Previously this would have
> > warned and crashed so it doesn't seem to occur in practice.
> 
> It could be triggered by a bad MFT cert. I added an error here.
>  
> > > +         mft_free(mft);
> > > +         X509_free(x509);
> > > +         return NULL;
> > > + }
> > >   crlfile = strrchr(c, '/');
> > >   if (crlfile != NULL)
> > >           crlfile++;
> > > @@ -1078,7 +1082,7 @@ proc_parser_file(char *file, unsigned ch
> > >           struct crl *c;
> > >           char *crl_uri;
> > >  
> > > -         crl_uri = x509_get_crl(x509, file);
> > > +         x509_get_crl(x509, file, &crl_uri);
> 
> Here luckily it does not matter, the code handles NULL just fine and fails
> on the verify because of the missing cert.
> 
> > >           parse_load_crl(crl_uri);
> > >           free(crl_uri);
> > >           if (auth_find(&auths, aki) == NULL)
> 
> > > - aia = strndup(
> > > + *aia = strndup(
> > >       ASN1_STRING_get0_data(ad->location->d.uniformResourceIdentifier),
> > >       ASN1_STRING_length(ad->location->d.uniformResourceIdentifier));
> > 
> > Unrelated to your diff: I think we may want to ensure that the URI doesn't
> > contain embedded NULs before calling strndup on it.
> 
> Maybe we need a function that does all this so it can be used in a few
> additional places. I would suggest to tackle this as a seperate diff.
>  

And here is the updated diff

-- 
:wq Claudio

Index: cert.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
retrieving revision 1.58
diff -u -p -r1.58 cert.c
--- cert.c      1 Apr 2022 13:27:38 -0000       1.58
+++ cert.c      1 Apr 2022 16:40:17 -0000
@@ -1052,13 +1052,10 @@ certificate_policies(struct parse *p, X5
 /*
  * Parse and partially validate an RPKI X509 certificate (either a trust
  * anchor or a certificate) as defined in RFC 6487.
- * If "ta" is set, this is a trust anchor and must be self-signed.
- * Returns the parse results or NULL on failure ("xp" will be NULL too).
- * On success, free the pointer with cert_free() and make sure that "xp"
- * is also dereferenced.
+ * Returns the parse results or NULL on failure.
  */
 static struct cert *
-cert_parse_inner(const char *fn, const unsigned char *der, size_t len, int ta)
+cert_parse_inner(const char *fn, const unsigned char *der, size_t len)
 {
        int              rc = 0, extsz, c;
        int              sia_present = 0;
@@ -1132,12 +1129,14 @@ cert_parse_inner(const char *fn, const u
                        goto out;
        }
 
-       p.res->aki = x509_get_aki(x, ta, p.fn);
-       p.res->ski = x509_get_ski(x, p.fn);
-       if (!ta) {
-               p.res->aia = x509_get_aia(x, p.fn);
-               p.res->crl = x509_get_crl(x, p.fn);
-       }
+       if (!x509_get_aki(x, p.fn, &p.res->aki))
+               goto out;
+       if (!x509_get_ski(x, p.fn, &p.res->ski))
+               goto out;
+       if (!x509_get_aia(x, p.fn, &p.res->aia))
+               goto out;
+       if (!x509_get_crl(x, p.fn, &p.res->crl))
+               goto out;
        if (!x509_get_expire(x, p.fn, &p.res->expires))
                goto out;
        p.res->purpose = x509_get_purpose(x, p.fn);
@@ -1198,7 +1197,7 @@ cert_parse(const char *fn, const unsigne
 {
        struct cert     *p;
 
-       if ((p = cert_parse_inner(fn, der, len, 0)) == NULL)
+       if ((p = cert_parse_inner(fn, der, len)) == NULL)
                return NULL;
 
        if (p->aki == NULL) {
@@ -1212,8 +1211,12 @@ cert_parse(const char *fn, const unsigne
                goto badcert;
        }
        if (p->aia == NULL) {
-               warnx("%s: RFC 6487 section 8.4.7: "
-                   "non-trust anchor missing AIA", fn);
+               warnx("%s: RFC 6487 section 8.4.7: AIA: extension missing", fn);
+               goto badcert;
+       }
+       if (p->crl == NULL) {
+               warnx("%s: RFC 6487 section 4.8.6: CRL: "
+                   "no CRL distribution point extension", fn);
                goto badcert;
        }
        return p;
@@ -1231,7 +1234,7 @@ ta_parse(const char *fn, const unsigned 
        EVP_PKEY        *pk = NULL, *opk = NULL;
        struct cert     *p;
 
-       if ((p = cert_parse_inner(fn, der, len, 1)) == NULL)
+       if ((p = cert_parse_inner(fn, der, len)) == NULL)
                return NULL;
 
        /* first check pubkey against the one from the TAL */
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.122
diff -u -p -r1.122 extern.h
--- extern.h    31 Mar 2022 12:00:00 -0000      1.122
+++ extern.h    1 Apr 2022 13:46:32 -0000
@@ -578,11 +578,11 @@ struct ibuf       *io_buf_recvfd(int, struct i
 /* X509 helpers. */
 
 void            x509_init_oid(void);
-char           *x509_get_aia(X509 *, const char *);
-char           *x509_get_aki(X509 *, int, const char *);
-char           *x509_get_ski(X509 *, const char *);
+int             x509_get_aia(X509 *, const char *, char **);
+int             x509_get_aki(X509 *, const char *, char **);
+int             x509_get_ski(X509 *, const char *, char **);
 int             x509_get_expire(X509 *, const char *, time_t *);
-char           *x509_get_crl(X509 *, const char *);
+int             x509_get_crl(X509 *, const char *, char **);
 char           *x509_crl_get_aki(X509_CRL *, const char *);
 char           *x509_get_pubkey(X509 *, const char *);
 enum cert_purpose       x509_get_purpose(X509 *, const char *);
Index: gbr.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/gbr.c,v
retrieving revision 1.14
diff -u -p -r1.14 gbr.c
--- gbr.c       18 Jan 2022 16:24:55 -0000      1.14
+++ gbr.c       1 Apr 2022 14:53:47 -0000
@@ -63,19 +63,24 @@ gbr_parse(X509 **x509, const char *fn, c
                err(1, NULL);
        free(cms);
 
-       p.res->aia = x509_get_aia(*x509, fn);
-       p.res->aki = x509_get_aki(*x509, 0, fn);
-       p.res->ski = x509_get_ski(*x509, fn);
+       if (!x509_get_aia(*x509, fn, &p.res->aia))
+               goto out;
+       if (!x509_get_aki(*x509, fn, &p.res->aki))
+               goto out;
+       if (!x509_get_ski(*x509, fn, &p.res->ski))
+               goto out;
        if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) {
                warnx("%s: RFC 6487 section 4.8: "
                    "missing AIA, AKI or SKI X509 extension", fn);
-               gbr_free(p.res);
-               X509_free(*x509);
-               *x509 = NULL;
-               return NULL;
+               goto out;
        }
-
        return p.res;
+
+out:
+       gbr_free(p.res);
+       X509_free(*x509);
+       *x509 = NULL;
+       return NULL;
 }
 
 /*
Index: mft.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v
retrieving revision 1.54
diff -u -p -r1.54 mft.c
--- mft.c       31 Mar 2022 12:00:00 -0000      1.54
+++ mft.c       1 Apr 2022 13:52:47 -0000
@@ -444,9 +444,12 @@ mft_parse(X509 **x509, const char *fn, c
        if ((p.res = calloc(1, sizeof(struct mft))) == NULL)
                err(1, NULL);
 
-       p.res->aia = x509_get_aia(*x509, fn);
-       p.res->aki = x509_get_aki(*x509, 0, fn);
-       p.res->ski = x509_get_ski(*x509, fn);
+       if (!x509_get_aia(*x509, fn, &p.res->aia))
+               goto out;
+       if (!x509_get_aki(*x509, fn, &p.res->aki))
+               goto out;
+       if (!x509_get_ski(*x509, fn, &p.res->ski))
+               goto out;
        if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) {
                warnx("%s: RFC 6487 section 4.8: "
                    "missing AIA, AKI or SKI X509 extension", fn);
Index: parser.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.64
diff -u -p -r1.64 parser.c
--- parser.c    10 Feb 2022 15:33:47 -0000      1.64
+++ parser.c    1 Apr 2022 16:53:39 -0000
@@ -360,7 +360,14 @@ proc_parser_mft_pre(char *file, const un
 
        a = valid_ski_aki(file, &auths, mft->ski, mft->aki);
        /* load CRL by hand, since it is referenced by the MFT itself */
-       c = x509_get_crl(x509, file);
+       if (!x509_get_crl(x509, file, &c) || c == NULL) {
+               if (c == NULL)
+                       warnx("%s: RFC 6487 section 4.8.6: CRL: "
+                           "no CRL distribution point extension", file);
+               mft_free(mft);
+               X509_free(x509);
+               return NULL;
+       }
        crlfile = strrchr(c, '/');
        if (crlfile != NULL)
                crlfile++;
@@ -1078,7 +1085,7 @@ proc_parser_file(char *file, unsigned ch
                struct crl *c;
                char *crl_uri;
 
-               crl_uri = x509_get_crl(x509, file);
+               x509_get_crl(x509, file, &crl_uri);
                parse_load_crl(crl_uri);
                free(crl_uri);
                if (auth_find(&auths, aki) == NULL)
Index: roa.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/roa.c,v
retrieving revision 1.38
diff -u -p -r1.38 roa.c
--- roa.c       10 Feb 2022 15:33:47 -0000      1.38
+++ roa.c       1 Apr 2022 14:00:48 -0000
@@ -351,9 +351,12 @@ roa_parse(X509 **x509, const char *fn, c
        if ((p.res = calloc(1, sizeof(struct roa))) == NULL)
                err(1, NULL);
 
-       p.res->aia = x509_get_aia(*x509, fn);
-       p.res->aki = x509_get_aki(*x509, 0, fn);
-       p.res->ski = x509_get_ski(*x509, fn);
+       if (!x509_get_aia(*x509, fn, &p.res->aia))
+               goto out;
+       if (!x509_get_aki(*x509, fn, &p.res->aki))
+               goto out;
+       if (!x509_get_ski(*x509, fn, &p.res->ski))
+               goto out;
        if (p.res->aia == NULL || p.res->aki == NULL || p.res->ski == NULL) {
                warnx("%s: RFC 6487 section 4.8: "
                    "missing AIA, AKI or SKI X509 extension", fn);
Index: x509.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/x509.c,v
retrieving revision 1.37
diff -u -p -r1.37 x509.c
--- x509.c      25 Mar 2022 08:19:04 -0000      1.37
+++ x509.c      1 Apr 2022 16:40:44 -0000
@@ -83,22 +83,18 @@ x509_init_oid(void)
  * Returns the AKI or NULL if it could not be parsed.
  * The AKI is formatted as a hex string.
  */
-char *
-x509_get_aki(X509 *x, int ta, const char *fn)
+int
+x509_get_aki(X509 *x, const char *fn, char **aki)
 {
        const unsigned char     *d;
        AUTHORITY_KEYID         *akid;
        ASN1_OCTET_STRING       *os;
-       int                      dsz, crit;
-       char                    *res = NULL;
+       int                      dsz, crit, rc = 0;
 
+       *aki = NULL;
        akid = X509_get_ext_d2i(x, NID_authority_key_identifier, &crit, NULL);
-       if (akid == NULL) {
-               if (!ta)
-                       warnx("%s: RFC 6487 section 4.8.3: AKI: "
-                           "extension missing", fn);
-               return NULL;
-       }
+       if (akid == NULL)
+               return 1;
        if (crit != 0) {
                warnx("%s: RFC 6487 section 4.8.3: "
                    "AKI: extension not non-critical", fn);
@@ -128,11 +124,11 @@ x509_get_aki(X509 *x, int ta, const char
                goto out;
        }
 
-       res = hex_encode(d, dsz);
-
+       *aki = hex_encode(d, dsz);
+       rc = 1;
 out:
        AUTHORITY_KEYID_free(akid);
-       return res;
+       return rc;
 }
 
 /*
@@ -140,19 +136,17 @@ out:
  * Returns the SKI or NULL if it could not be parsed.
  * The SKI is formatted as a hex string.
  */
-char *
-x509_get_ski(X509 *x, const char *fn)
+int
+x509_get_ski(X509 *x, const char *fn, char **ski)
 {
        const unsigned char     *d;
        ASN1_OCTET_STRING       *os;
-       int                      dsz, crit;
-       char                    *res = NULL;
+       int                      dsz, crit, rc = 0;
 
+       *ski = NULL;
        os = X509_get_ext_d2i(x, NID_subject_key_identifier, &crit, NULL);
-       if (os == NULL) {
-               warnx("%s: RFC 6487 section 4.8.2: SKI: extension missing", fn);
-               return NULL;
-       }
+       if (os == NULL)
+               return 1;
        if (crit != 0) {
                warnx("%s: RFC 6487 section 4.8.2: "
                    "SKI: extension not non-critical", fn);
@@ -169,10 +163,11 @@ x509_get_ski(X509 *x, const char *fn)
                goto out;
        }
 
-       res = hex_encode(d, dsz);
+       *ski = hex_encode(d, dsz);
+       rc = 1;
 out:
        ASN1_OCTET_STRING_free(os);
-       return res;
+       return rc;
 }
 
 /*
@@ -281,19 +276,18 @@ x509_get_pubkey(X509 *x, const char *fn)
  * Returns NULL on failure, on success returns the AIA URI
  * (which has to be freed after use).
  */
-char *
-x509_get_aia(X509 *x, const char *fn)
+int
+x509_get_aia(X509 *x, const char *fn, char **aia)
 {
        ACCESS_DESCRIPTION              *ad;
        AUTHORITY_INFO_ACCESS           *info;
-       char                            *aia = NULL;
-       int                              crit;
+       int                              crit, rc = 0;
 
+       *aia = NULL;
        info = X509_get_ext_d2i(x, NID_info_access, &crit, NULL);
-       if (info == NULL) {
-               warnx("%s: RFC 6487 section 4.8.7: AIA: extension missing", fn);
-               return NULL;
-       }
+       if (info == NULL)
+               return 1;
+
        if (crit != 0) {
                warnx("%s: RFC 6487 section 4.8.7: "
                    "AIA: extension not non-critical", fn);
@@ -325,15 +319,16 @@ x509_get_aia(X509 *x, const char *fn)
                goto out;
        }
 
-       aia = strndup(
+       *aia = strndup(
            ASN1_STRING_get0_data(ad->location->d.uniformResourceIdentifier),
            ASN1_STRING_length(ad->location->d.uniformResourceIdentifier));
-       if (aia == NULL)
+       if (*aia == NULL)
                err(1, NULL);
+       rc = 1;
 
 out:
        AUTHORITY_INFO_ACCESS_free(info);
-       return aia;
+       return rc;
 }
 
 /*
@@ -364,21 +359,19 @@ x509_get_expire(X509 *x, const char *fn,
  * Returns NULL on failure, the crl URI on success which has to be freed
  * after use.
  */
-char *
-x509_get_crl(X509 *x, const char *fn)
+int
+x509_get_crl(X509 *x, const char *fn, char **crl)
 {
        CRL_DIST_POINTS         *crldp;
        DIST_POINT              *dp;
        GENERAL_NAME            *name;
-       char                    *crl = NULL;
-       int                      crit;
+       int                      crit, rc = 0;
 
+       *crl = NULL;
        crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, &crit, NULL);
-       if (crldp == NULL) {
-               warnx("%s: RFC 6487 section 4.8.6: CRL: "
-                   "no CRL distribution point extension", fn);
-               return NULL;
-       }
+       if (crldp == NULL)
+               return 1;
+
        if (crit != 0) {
                warnx("%s: RFC 6487 section 4.8.6: "
                    "CRL distribution point: extension not non-critical", fn);
@@ -425,14 +418,15 @@ x509_get_crl(X509 *x, const char *fn)
                goto out;
        }
 
-       crl = strndup(ASN1_STRING_get0_data(name->d.uniformResourceIdentifier),
+       *crl = strndup(ASN1_STRING_get0_data(name->d.uniformResourceIdentifier),
            ASN1_STRING_length(name->d.uniformResourceIdentifier));
-       if (crl == NULL)
+       if (*crl == NULL)
                err(1, NULL);
+       rc = 1;
 
 out:
        CRL_DIST_POINTS_free(crldp);
-       return crl;
+       return rc;
 }
 
 /*

Reply via email to