Re: rpki-client x509 verification in common function

2022-01-19 Thread Claudio Jeker
On Tue, Jan 18, 2022 at 02:41:38PM +0100, Claudio Jeker wrote:
> On Tue, Jan 18, 2022 at 02:09:08PM +0100, Theo Buehler wrote:
> > On Tue, Jan 18, 2022 at 12:16:44PM +0100, Claudio Jeker wrote:
> > > How X509_verify_cert() is called in rpki-client is mostly the same in all
> > > places so move all this X509 boilerplate into valid_x509().
> > > 
> > > This simplifies the x509 validation in the parser a fair but and will also
> > > make it easier for -f to validate certs.
> > > 
> > > OK?
> > 
> > ok
> > 
> > I would suggest we merge the three if (crl != NULL) checks into one
> > (maybe in a follow-up).
> 
> Sure, I tried to keep this as mechanical as possible since this is nasty
> code that does not permit errors.
>  
> > The _roa and _gbr paths called the warnx() with the
> > X509_verify_cert_error_string() only conditionally. I guess we can
> > adjust that later if this turns out to be too noisy.
>  
> Yes, I forgot to mention that. I think this are some left-overs from the
> time where CRLs were optional. At least I see no reason why
> X509_V_ERR_UNABLE_TO_GET_CRL errors are only printed at verbose level 1 or
> higher.

I looked a bit more into this. So I added this reduced verbosity in Rev
1.17 of main.c. This was before the Elk Lakes hackathon that fixed most of
the validation code. For example in Rev 1.39 of main a few months later the
lookup of CRLs changed to use the AKI for lookups and away from using some
sort of normalized name. I think this and some of the later diffs made
this workaround obsolete.

-- 
:wq Claudio



Re: rpki-client x509 verification in common function

2022-01-18 Thread Claudio Jeker
On Tue, Jan 18, 2022 at 02:09:08PM +0100, Theo Buehler wrote:
> On Tue, Jan 18, 2022 at 12:16:44PM +0100, Claudio Jeker wrote:
> > How X509_verify_cert() is called in rpki-client is mostly the same in all
> > places so move all this X509 boilerplate into valid_x509().
> > 
> > This simplifies the x509 validation in the parser a fair but and will also
> > make it easier for -f to validate certs.
> > 
> > OK?
> 
> ok
> 
> I would suggest we merge the three if (crl != NULL) checks into one
> (maybe in a follow-up).

Sure, I tried to keep this as mechanical as possible since this is nasty
code that does not permit errors.
 
> The _roa and _gbr paths called the warnx() with the
> X509_verify_cert_error_string() only conditionally. I guess we can
> adjust that later if this turns out to be too noisy.
 
Yes, I forgot to mention that. I think this are some left-overs from the
time where CRLs were optional. At least I see no reason why
X509_V_ERR_UNABLE_TO_GET_CRL errors are only printed at verbose level 1 or
higher.
 
> > -- 
> > :wq Claudio
> > 
> > Index: parser.c
> > ===
> > RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
> > retrieving revision 1.37
> > diff -u -p -r1.37 parser.c
> > --- parser.c14 Jan 2022 15:00:23 -  1.37
> > +++ parser.c18 Jan 2022 11:01:45 -
> > @@ -200,52 +200,74 @@ verify_cb(int ok, X509_STORE_CTX *store_
> >  }
> >  
> >  /*
> > - * Parse and validate a ROA.
> > - * This is standard stuff.
> > - * Returns the roa on success, NULL on failure.
> > + * Validate the X509 certificate.  If crl is NULL don't check CRL.
> > + * Returns 1 for valid certificates, returns 0 if there is a verify error
> >   */
> > -static struct roa *
> > -proc_parser_roa(char *file, const unsigned char *der, size_t len)
> > +static int
> > +valid_x509(char *file, X509 *x509, struct auth *a, struct crl *crl)
> >  {
> > -   struct roa  *roa;
> > -   X509*x509;
> > -   int  c;
> > -   struct auth *a;
> > STACK_OF(X509)  *chain;
> > -   STACK_OF(X509_CRL)  *crls;
> > -   struct crl  *crl;
> > -
> > -   if ((roa = roa_parse(, file, der, len)) == NULL)
> > -   return NULL;
> > +   STACK_OF(X509_CRL)  *crls = NULL;
> > +   int  c;
> >  
> > -   a = valid_ski_aki(file, , roa->ski, roa->aki);
> > build_chain(a, );
> > -   crl = get_crl(a);
> > -   build_crls(crl, );
> > +   if (crl != NULL)
> > +   build_crls(crl, );
> >  
> > assert(x509 != NULL);
> > if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
> > cryptoerrx("X509_STORE_CTX_init");
> > +
> > X509_STORE_CTX_set_verify_cb(ctx, verify_cb);
> > if (!X509_STORE_CTX_set_app_data(ctx, file))
> > cryptoerrx("X509_STORE_CTX_set_app_data");
> > -   X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CRL_CHECK);
> > +   if (crl != NULL)
> > +   X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CRL_CHECK);
> > X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
> > X509_STORE_CTX_set0_trusted_stack(ctx, chain);
> > -   X509_STORE_CTX_set0_crls(ctx, crls);
> > +   if (crl != NULL)
> > +   X509_STORE_CTX_set0_crls(ctx, crls);
> >  
> > if (X509_verify_cert(ctx) <= 0) {
> > c = X509_STORE_CTX_get_error(ctx);
> > +   warnx("%s: %s", file, X509_verify_cert_error_string(c));
> > X509_STORE_CTX_cleanup(ctx);
> > -   if (verbose > 0 || c != X509_V_ERR_UNABLE_TO_GET_CRL)
> > -   warnx("%s: %s", file, X509_verify_cert_error_string(c));
> > -   X509_free(x509);
> > -   roa_free(roa);
> > sk_X509_free(chain);
> > sk_X509_CRL_free(crls);
> > -   return NULL;
> > +   return 0;
> > }
> > +
> > X509_STORE_CTX_cleanup(ctx);
> > +   sk_X509_free(chain);
> > +   sk_X509_CRL_free(crls);
> > +   return 1;
> > +}
> > +
> > +/*
> > + * Parse and validate a ROA.
> > + * This is standard stuff.
> > + * Returns the roa on success, NULL on failure.
> > + */
> > +static struct roa *
> > +proc_parser_roa(char *file, const unsigned char *der, size_t len)
> > +{
> > +   struct roa  *roa;
> > +   struct crl  *crl;
> > +   struct auth *a;
> > +   X509*x509;
> > +
> > +   if ((roa = roa_parse(, file, der, len)) == NULL)
> > +   return NULL;
> > +
> > +   a = valid_ski_aki(file, , roa->ski, roa->aki);
> > +   crl = get_crl(a);
> > +
> > +   if (!valid_x509(file, x509, a, crl)) {
> > +   X509_free(x509);
> > +   roa_free(roa);
> > +   return NULL;
> > +   }
> > +   X509_free(x509);
> >  
> > /*
> >  * Check CRL to figure out the soonest transitive expiry moment
> > @@ -270,10 +292,6 @@ proc_parser_roa(char *file, const unsign
> > if (valid_roa(file, , roa))
> > roa->valid = 1;
> >  
> > -   sk_X509_free(chain);
> 

Re: rpki-client x509 verification in common function

2022-01-18 Thread Theo Buehler
On Tue, Jan 18, 2022 at 12:16:44PM +0100, Claudio Jeker wrote:
> How X509_verify_cert() is called in rpki-client is mostly the same in all
> places so move all this X509 boilerplate into valid_x509().
> 
> This simplifies the x509 validation in the parser a fair but and will also
> make it easier for -f to validate certs.
> 
> OK?

ok

I would suggest we merge the three if (crl != NULL) checks into one
(maybe in a follow-up).

The _roa and _gbr paths called the warnx() with the
X509_verify_cert_error_string() only conditionally. I guess we can
adjust that later if this turns out to be too noisy.


> -- 
> :wq Claudio
> 
> Index: parser.c
> ===
> RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
> retrieving revision 1.37
> diff -u -p -r1.37 parser.c
> --- parser.c  14 Jan 2022 15:00:23 -  1.37
> +++ parser.c  18 Jan 2022 11:01:45 -
> @@ -200,52 +200,74 @@ verify_cb(int ok, X509_STORE_CTX *store_
>  }
>  
>  /*
> - * Parse and validate a ROA.
> - * This is standard stuff.
> - * Returns the roa on success, NULL on failure.
> + * Validate the X509 certificate.  If crl is NULL don't check CRL.
> + * Returns 1 for valid certificates, returns 0 if there is a verify error
>   */
> -static struct roa *
> -proc_parser_roa(char *file, const unsigned char *der, size_t len)
> +static int
> +valid_x509(char *file, X509 *x509, struct auth *a, struct crl *crl)
>  {
> - struct roa  *roa;
> - X509*x509;
> - int  c;
> - struct auth *a;
>   STACK_OF(X509)  *chain;
> - STACK_OF(X509_CRL)  *crls;
> - struct crl  *crl;
> -
> - if ((roa = roa_parse(, file, der, len)) == NULL)
> - return NULL;
> + STACK_OF(X509_CRL)  *crls = NULL;
> + int  c;
>  
> - a = valid_ski_aki(file, , roa->ski, roa->aki);
>   build_chain(a, );
> - crl = get_crl(a);
> - build_crls(crl, );
> + if (crl != NULL)
> + build_crls(crl, );
>  
>   assert(x509 != NULL);
>   if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
>   cryptoerrx("X509_STORE_CTX_init");
> +
>   X509_STORE_CTX_set_verify_cb(ctx, verify_cb);
>   if (!X509_STORE_CTX_set_app_data(ctx, file))
>   cryptoerrx("X509_STORE_CTX_set_app_data");
> - X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CRL_CHECK);
> + if (crl != NULL)
> + X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CRL_CHECK);
>   X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
>   X509_STORE_CTX_set0_trusted_stack(ctx, chain);
> - X509_STORE_CTX_set0_crls(ctx, crls);
> + if (crl != NULL)
> + X509_STORE_CTX_set0_crls(ctx, crls);
>  
>   if (X509_verify_cert(ctx) <= 0) {
>   c = X509_STORE_CTX_get_error(ctx);
> + warnx("%s: %s", file, X509_verify_cert_error_string(c));
>   X509_STORE_CTX_cleanup(ctx);
> - if (verbose > 0 || c != X509_V_ERR_UNABLE_TO_GET_CRL)
> - warnx("%s: %s", file, X509_verify_cert_error_string(c));
> - X509_free(x509);
> - roa_free(roa);
>   sk_X509_free(chain);
>   sk_X509_CRL_free(crls);
> - return NULL;
> + return 0;
>   }
> +
>   X509_STORE_CTX_cleanup(ctx);
> + sk_X509_free(chain);
> + sk_X509_CRL_free(crls);
> + return 1;
> +}
> +
> +/*
> + * Parse and validate a ROA.
> + * This is standard stuff.
> + * Returns the roa on success, NULL on failure.
> + */
> +static struct roa *
> +proc_parser_roa(char *file, const unsigned char *der, size_t len)
> +{
> + struct roa  *roa;
> + struct crl  *crl;
> + struct auth *a;
> + X509*x509;
> +
> + if ((roa = roa_parse(, file, der, len)) == NULL)
> + return NULL;
> +
> + a = valid_ski_aki(file, , roa->ski, roa->aki);
> + crl = get_crl(a);
> +
> + if (!valid_x509(file, x509, a, crl)) {
> + X509_free(x509);
> + roa_free(roa);
> + return NULL;
> + }
> + X509_free(x509);
>  
>   /*
>* Check CRL to figure out the soonest transitive expiry moment
> @@ -270,10 +292,6 @@ proc_parser_roa(char *file, const unsign
>   if (valid_roa(file, , roa))
>   roa->valid = 1;
>  
> - sk_X509_free(chain);
> - sk_X509_CRL_free(crls);
> - X509_free(x509);
> -
>   return roa;
>  }
>  
> @@ -336,38 +354,18 @@ proc_parser_mft(char *file, const unsign
>  {
>   struct mft  *mft;
>   X509*x509;
> - int  c;
>   struct auth *a;
> - STACK_OF(X509)  *chain;
>  
>   if ((mft = mft_parse(, file, der, len)) == NULL)
>   return NULL;
>  
>   a = valid_ski_aki(file, , mft->ski, mft->aki);
> - build_chain(a, );
>  
> 

rpki-client x509 verification in common function

2022-01-18 Thread Claudio Jeker
How X509_verify_cert() is called in rpki-client is mostly the same in all
places so move all this X509 boilerplate into valid_x509().

This simplifies the x509 validation in the parser a fair but and will also
make it easier for -f to validate certs.

OK?
-- 
:wq Claudio

Index: parser.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.37
diff -u -p -r1.37 parser.c
--- parser.c14 Jan 2022 15:00:23 -  1.37
+++ parser.c18 Jan 2022 11:01:45 -
@@ -200,52 +200,74 @@ verify_cb(int ok, X509_STORE_CTX *store_
 }
 
 /*
- * Parse and validate a ROA.
- * This is standard stuff.
- * Returns the roa on success, NULL on failure.
+ * Validate the X509 certificate.  If crl is NULL don't check CRL.
+ * Returns 1 for valid certificates, returns 0 if there is a verify error
  */
-static struct roa *
-proc_parser_roa(char *file, const unsigned char *der, size_t len)
+static int
+valid_x509(char *file, X509 *x509, struct auth *a, struct crl *crl)
 {
-   struct roa  *roa;
-   X509*x509;
-   int  c;
-   struct auth *a;
STACK_OF(X509)  *chain;
-   STACK_OF(X509_CRL)  *crls;
-   struct crl  *crl;
-
-   if ((roa = roa_parse(, file, der, len)) == NULL)
-   return NULL;
+   STACK_OF(X509_CRL)  *crls = NULL;
+   int  c;
 
-   a = valid_ski_aki(file, , roa->ski, roa->aki);
build_chain(a, );
-   crl = get_crl(a);
-   build_crls(crl, );
+   if (crl != NULL)
+   build_crls(crl, );
 
assert(x509 != NULL);
if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
cryptoerrx("X509_STORE_CTX_init");
+
X509_STORE_CTX_set_verify_cb(ctx, verify_cb);
if (!X509_STORE_CTX_set_app_data(ctx, file))
cryptoerrx("X509_STORE_CTX_set_app_data");
-   X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CRL_CHECK);
+   if (crl != NULL)
+   X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_CRL_CHECK);
X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
X509_STORE_CTX_set0_trusted_stack(ctx, chain);
-   X509_STORE_CTX_set0_crls(ctx, crls);
+   if (crl != NULL)
+   X509_STORE_CTX_set0_crls(ctx, crls);
 
if (X509_verify_cert(ctx) <= 0) {
c = X509_STORE_CTX_get_error(ctx);
+   warnx("%s: %s", file, X509_verify_cert_error_string(c));
X509_STORE_CTX_cleanup(ctx);
-   if (verbose > 0 || c != X509_V_ERR_UNABLE_TO_GET_CRL)
-   warnx("%s: %s", file, X509_verify_cert_error_string(c));
-   X509_free(x509);
-   roa_free(roa);
sk_X509_free(chain);
sk_X509_CRL_free(crls);
-   return NULL;
+   return 0;
}
+
X509_STORE_CTX_cleanup(ctx);
+   sk_X509_free(chain);
+   sk_X509_CRL_free(crls);
+   return 1;
+}
+
+/*
+ * Parse and validate a ROA.
+ * This is standard stuff.
+ * Returns the roa on success, NULL on failure.
+ */
+static struct roa *
+proc_parser_roa(char *file, const unsigned char *der, size_t len)
+{
+   struct roa  *roa;
+   struct crl  *crl;
+   struct auth *a;
+   X509*x509;
+
+   if ((roa = roa_parse(, file, der, len)) == NULL)
+   return NULL;
+
+   a = valid_ski_aki(file, , roa->ski, roa->aki);
+   crl = get_crl(a);
+
+   if (!valid_x509(file, x509, a, crl)) {
+   X509_free(x509);
+   roa_free(roa);
+   return NULL;
+   }
+   X509_free(x509);
 
/*
 * Check CRL to figure out the soonest transitive expiry moment
@@ -270,10 +292,6 @@ proc_parser_roa(char *file, const unsign
if (valid_roa(file, , roa))
roa->valid = 1;
 
-   sk_X509_free(chain);
-   sk_X509_CRL_free(crls);
-   X509_free(x509);
-
return roa;
 }
 
@@ -336,38 +354,18 @@ proc_parser_mft(char *file, const unsign
 {
struct mft  *mft;
X509*x509;
-   int  c;
struct auth *a;
-   STACK_OF(X509)  *chain;
 
if ((mft = mft_parse(, file, der, len)) == NULL)
return NULL;
 
a = valid_ski_aki(file, , mft->ski, mft->aki);
-   build_chain(a, );
 
-   if (!X509_STORE_CTX_init(ctx, NULL, x509, NULL))
-   cryptoerrx("X509_STORE_CTX_init");
-
-   /* CRL checks disabled here because CRL is referenced from mft */
-   X509_STORE_CTX_set_verify_cb(ctx, verify_cb);
-   if (!X509_STORE_CTX_set_app_data(ctx, file))
-   cryptoerrx("X509_STORE_CTX_set_app_data");
-   X509_STORE_CTX_set_depth(ctx, MAX_CERT_DEPTH);
-   X509_STORE_CTX_set0_trusted_stack(ctx,