On Thu, Apr 21, 2022 at 01:14:31PM +0200, Claudio Jeker wrote:
> So here is the cleanup of filemode.c and also a bit of cleanup in parse.c
> This should also fix a few bugs in parse_load_certchain() (mainly
> memleaks).

A couple of suggestions for parse_load_certchain() below.

ok

> 
> -- 
> :wq Claudio
> 
> Index: cert.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
> retrieving revision 1.70
> diff -u -p -r1.70 cert.c
> --- cert.c    21 Apr 2022 09:53:07 -0000      1.70
> +++ cert.c    21 Apr 2022 10:45:17 -0000
> @@ -999,6 +999,9 @@ out:
>  struct cert *
>  cert_parse(const char *fn, struct cert *p)
>  {
> +     if (p == NULL)
> +             return NULL;
> +
>       if (p->aki == NULL) {
>               warnx("%s: RFC 6487 section 8.4.2: "
>                   "non-trust anchor missing AKI", fn);
> @@ -1032,6 +1035,9 @@ ta_parse(const char *fn, struct cert *p,
>       ASN1_TIME       *notBefore, *notAfter;
>       EVP_PKEY        *pk, *opk;
>  
> +     if (p == NULL)
> +             return NULL;
> +
>       /* first check pubkey against the one from the TAL */
>       pk = d2i_PUBKEY(NULL, &pkey, pkeysz);
>       if (pk == NULL) {
> @@ -1207,7 +1213,7 @@ auth_find(struct auth_tree *auths, const
>       return RB_FIND(auth_tree, auths, &a);
>  }
>  
> -void
> +struct auth *
>  auth_insert(struct auth_tree *auths, struct cert *cert, struct auth *parent)
>  {
>       struct auth *na;
> @@ -1221,6 +1227,8 @@ auth_insert(struct auth_tree *auths, str
>  
>       if (RB_INSERT(auth_tree, auths, na) != NULL)
>               err(1, "auth tree corrupted");
> +
> +     return na;
>  }
>  
>  static void
> Index: extern.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
> retrieving revision 1.131
> diff -u -p -r1.131 extern.h
> --- extern.h  21 Apr 2022 09:53:07 -0000      1.131
> +++ extern.h  21 Apr 2022 10:46:09 -0000
> @@ -308,7 +308,7 @@ struct auth {
>  RB_HEAD(auth_tree, auth);
>  
>  struct auth  *auth_find(struct auth_tree *, const char *);
> -void          auth_insert(struct auth_tree *, struct cert *, struct auth *);
> +struct auth  *auth_insert(struct auth_tree *, struct cert *, struct auth *);
>  
>  enum http_result {
>       HTTP_FAILED,    /* anything else */
> Index: filemode.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/filemode.c,v
> retrieving revision 1.1
> diff -u -p -r1.1 filemode.c
> --- filemode.c        21 Apr 2022 09:53:07 -0000      1.1
> +++ filemode.c        21 Apr 2022 10:47:24 -0000
> @@ -46,80 +46,6 @@ static struct crl_tree      crlt = RB_INITIA
>  struct tal           *talobj[TALSZ_MAX];
>  
>  /*
> - * Validate a certificate, if invalid free the resouces and return NULL.
> - */
> -static struct cert *
> -proc_parser_cert_validate(char *file, struct cert *cert)
> -{
> -     struct auth     *a;
> -     struct crl      *crl;
> -
> -     a = valid_ski_aki(file, &auths, cert->ski, cert->aki);
> -     crl = crl_get(&crlt, a);
> -
> -     if (!valid_x509(file, ctx, cert->x509, a, crl, 0)) {
> -             cert_free(cert);
> -             return NULL;
> -     }
> -
> -     cert->talid = a->cert->talid;
> -
> -     /* Validate the cert */
> -     if (!valid_cert(file, a, cert)) {
> -             cert_free(cert);
> -             return NULL;
> -     }
> -
> -     /*
> -      * Add validated CA certs to the RPKI auth tree.
> -      */
> -     if (cert->purpose == CERT_PURPOSE_CA)
> -             auth_insert(&auths, cert, a);
> -
> -     return cert;
> -}
> -
> -/*
> - * Root certificates come from TALs (has a pkey and is self-signed).
> - * Parse the certificate, ensure that its public key matches the
> - * known public key from the TAL, and then validate the RPKI
> - * content.
> - *
> - * This returns a certificate (which must not be freed) or NULL on
> - * parse failure.
> - */
> -static struct cert *
> -proc_parser_root_cert(char *file, const unsigned char *der, size_t len,
> -    unsigned char *pkey, size_t pkeysz, int talid)
> -{
> -     struct cert             *cert;
> -
> -     /* Extract certificate data. */
> -
> -     cert = cert_parse_pre(file, der, len);
> -     if (cert == NULL)
> -             return NULL;
> -     cert = ta_parse(file, cert, pkey, pkeysz);
> -     if (cert == NULL)
> -             return NULL;
> -
> -     if (!valid_ta(file, &auths, cert)) {
> -             warnx("%s: certificate not a valid ta", file);
> -             cert_free(cert);
> -             return NULL;
> -     }
> -
> -     cert->talid = talid;
> -
> -     /*
> -      * Add valid roots to the RPKI auth tree.
> -      */
> -     auth_insert(&auths, cert, NULL);
> -
> -     return cert;
> -}
> -
> -/*
>   * Use the X509 CRL Distribution Points to locate the CRL needed for
>   * verification.
>   */
> @@ -207,25 +133,25 @@ parse_load_cert(char *uri)
>  static void
>  parse_load_certchain(char *uri)
>  {
> -     struct cert *stack[MAX_CERT_DEPTH];
> +     struct cert *stack[MAX_CERT_DEPTH] = { 0 };
>       char *filestack[MAX_CERT_DEPTH];
>       struct cert *cert;
> -     int i, failed;
> +     struct crl *crl;
> +     struct auth *a;
> +     int i;
>  
>       for (i = 0; i < MAX_CERT_DEPTH; i++) {
> -             cert = parse_load_cert(uri);
> -             if (cert == NULL) {
> +             filestack[i] = uri;
> +             stack[i] = cert = parse_load_cert(uri);
> +             if (cert == NULL || cert->purpose != CERT_PURPOSE_CA) {
>                       warnx("failed to build authority chain");
> -                     return;
> +                     goto fail;
>               }
>               if (auth_find(&auths, cert->ski) != NULL) {
>                       assert(i == 0);
> -                     cert_free(cert);
> -                     return; /* cert already added */
> +                     goto fail;
>               }
> -             stack[i] = cert;
> -             filestack[i] = uri;
> -             if (auth_find(&auths, cert->aki) != NULL)
> +             if ((a = auth_find(&auths, cert->aki)) != NULL)
>                       break;  /* found chain to TA */
>               uri = cert->aia;
>       }
> @@ -233,47 +159,65 @@ parse_load_certchain(char *uri)
>       if (i >= MAX_CERT_DEPTH) {
>               warnx("authority chain exceeds max depth of %d",
>                   MAX_CERT_DEPTH);

I would prefer to move this cleanup to the end of the function and
have a goto fail here.

> +fail:
>               for (i = 0; i < MAX_CERT_DEPTH; i++)
>                       cert_free(stack[i]);
>               return;
>       }
>  
>       /* TA found play back the stack and add all certs */
> -     for (failed = 0; i >= 0; i--) {
> +     for (; i >= 0; i--) {
>               cert = stack[i];
>               uri = filestack[i];
>  
> -             if (failed)
> -                     cert_free(cert);
> -             else if (proc_parser_cert_validate(uri, cert) == NULL)
> -                     failed = 1;
> +             crl = crl_get(&crlt, a);

I think this loop is easier to understand:

        for (; i >= 0; i--) {
                cert = stack[i];
                uri = filestack[i];

                crl = crl_get(&crlt, a);
                if (!valid_x509(uri, ctx, cert->x509, a, crl, 0) ||
                    !valid_cert(uri, a, cert))
                        goto fail;

                cert->talid = a->cert->talid;
                a = auth_insert(&auths, cert, a);
                stack[i] = NULL;
        }

> +             if (valid_x509(uri, ctx, cert->x509, a, crl, 0) &&
> +                 valid_cert(uri, a, cert)) {
> +                     cert->talid = a->cert->talid;
> +                     a = auth_insert(&auths, cert, a);
> +             } else {
> +                     for (; i >= 0; i--)
> +                             cert_free(stack[i]);
> +             }
>       }
>  }
>  
>  static void
>  parse_load_ta(struct tal *tal)
>  {
> -     const char *file;
> -     char *nfile, *f;
> +     const char *filename;
> +     struct cert *cert;
> +     unsigned char *f = NULL;
> +     char *file;
>       size_t flen;
>  
>       /* does not matter which URI, all end with same filename */
> -     file = strrchr(tal->uri[0], '/');
> -     assert(file);
> +     filename = strrchr(tal->uri[0], '/');
> +     assert(filename);
>  
> -     if (asprintf(&nfile, "ta/%s%s", tal->descr, file) == -1)
> +     if (asprintf(&file, "ta/%s%s", tal->descr, filename) == -1)
>               err(1, NULL);
>  
> -     f = load_file(nfile, &flen);
> +     f = load_file(file, &flen);
>       if (f == NULL) {
> -             warn("parse file %s", nfile);
> -             free(nfile);
> -             return;
> +             warn("parse file %s", file);
> +             goto out;
>       }
>  
> -     /* if TA is valid it was added as a root which is all we need */
> -     proc_parser_root_cert(nfile, f, flen, tal->pkey, tal->pkeysz, tal->id);
> -     free(nfile);
> +     /* Extract certificate data. */
> +     cert = cert_parse_pre(file, f, flen);
> +     cert = ta_parse(file, cert, tal->pkey, tal->pkeysz);
> +     if (cert == NULL)
> +             goto out;
> +
> +     cert->talid = tal->id;
> +
> +     if (!valid_ta(file, &auths, cert))
> +             cert_free(cert);
> +     else
> +             auth_insert(&auths, cert, NULL);
> +out:
> +     free(file);
>       free(f);
>  }
>  
> Index: parser.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
> retrieving revision 1.72
> diff -u -p -r1.72 parser.c
> --- parser.c  21 Apr 2022 09:53:07 -0000      1.72
> +++ parser.c  21 Apr 2022 10:45:53 -0000
> @@ -389,30 +389,37 @@ proc_parser_mft(struct entity *entp, str
>  }
>  
>  /*
> - * Validate a certificate, if invalid free the resouces and return NULL.
> + * Certificates are from manifests (has a digest and is signed with
> + * another certificate) Parse the certificate, make sure its
> + * signatures are valid (with CRLs), then validate the RPKI content.
> + * This returns a certificate (which must not be freed) or NULL on
> + * parse failure.
>   */
>  static struct cert *
> -proc_parser_cert_validate(char *file, struct cert *cert)
> +proc_parser_cert(char *file, const unsigned char *der, size_t len)
>  {
> -     struct auth     *a;
> +     struct cert     *cert;
>       struct crl      *crl;
> +     struct auth     *a;
> +
> +     /* Extract certificate data. */
> +
> +     cert = cert_parse_pre(file, der, len);
> +     cert = cert_parse(file, cert);
> +     if (cert == NULL)
> +             return NULL;
>  
>       a = valid_ski_aki(file, &auths, cert->ski, cert->aki);
>       crl = crl_get(&crlt, a);
>  
> -     if (!valid_x509(file, ctx, cert->x509, a, crl, 0)) {
> +     if (!valid_x509(file, ctx, cert->x509, a, crl, 0) ||
> +         !valid_cert(file, a, cert)) {
>               cert_free(cert);
>               return NULL;
>       }
>  
>       cert->talid = a->cert->talid;
>  
> -     /* Validate the cert */
> -     if (!valid_cert(file, a, cert)) {
> -             cert_free(cert);
> -             return NULL;
> -     }
> -
>       /*
>        * Add validated CA certs to the RPKI auth tree.
>        */
> @@ -423,31 +430,6 @@ proc_parser_cert_validate(char *file, st
>  }
>  
>  /*
> - * Certificates are from manifests (has a digest and is signed with
> - * another certificate) Parse the certificate, make sure its
> - * signatures are valid (with CRLs), then validate the RPKI content.
> - * This returns a certificate (which must not be freed) or NULL on
> - * parse failure.
> - */
> -static struct cert *
> -proc_parser_cert(char *file, const unsigned char *der, size_t len)
> -{
> -     struct cert     *cert;
> -
> -     /* Extract certificate data. */
> -
> -     cert = cert_parse_pre(file, der, len);
> -     if (cert == NULL)
> -             return NULL;
> -     cert = cert_parse(file, cert);
> -     if (cert == NULL)
> -             return NULL;
> -
> -     cert = proc_parser_cert_validate(file, cert);
> -     return cert;
> -}
> -
> -/*
>   * Root certificates come from TALs (has a pkey and is self-signed).
>   * Parse the certificate, ensure that its public key matches the
>   * known public key from the TAL, and then validate the RPKI
> @@ -465,8 +447,6 @@ proc_parser_root_cert(char *file, const 
>       /* Extract certificate data. */
>  
>       cert = cert_parse_pre(file, der, len);
> -     if (cert == NULL)
> -             return NULL;
>       cert = ta_parse(file, cert, pkey, pkeysz);
>       if (cert == NULL)
>               return NULL;
> 

Reply via email to