On Wed, Feb 24, 2021 at 09:21:56PM +0100, Theo Buehler wrote:
> On Wed, Feb 24, 2021 at 09:00:05PM +0100, Theo Buehler wrote:
> > On Wed, Feb 24, 2021 at 06:47:00AM +0100, Jan Klemkow wrote:
> > > another co-worker of mine has found an other regress in the LibreSSL
> > > legacy verifier.  I took his diff and made a test for our regression
> > > framework.
> > > 
> > > The legacy verifier seems not to check the certificate if no root CA was
> > > given.  The following test creates an expired certificate and tries to
> > > verify it.  In one case it found the expected error in another, it does
> > > not.
> > 
> > Thanks for the report and the test case, that's very helpful. The diff
> > at the end addresses this.
> > 
> > The verifier does not find the expected error because it now bails out
> > earlier.  This is a consequence of a refactoring of X509_verify_cert()
> > (x509_vfy.c r1.75) that was done to integrate the new verifier.
> > 
> > https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libcrypto/x509/x509_vfy.c.diff?r1=1.74&r2=1.75
> > 
> > What happens is that x509_legacy_verify_build_chain() returns ok == 0 in
> > your test case. The safety net at the end of x509_verify_cert_legacy()
> > sets ctx->error to X509_V_ERR_UNSPECIFIED (so the unchecked call to
> > X509_verify_cert() in your regress test actually indicates verification
> > failure).
> > 
> > 
> > The diff below restores the previous behavior and fixes a bug.
> > 
> > Prior to the the refactoring, each 'goto end' in the code that is now in
> > x509_legacy_verify_build_chain() would stop validation, while in other
> > cases validation would have carried on. So indicate this via the return
> > value and return ok via a pointer.
> > 
> > The bug is that the return value check of x509_legacy_verify_build_chain()
> > should have been if (ok <= 0), not if (!ok).
> > 
> > Regarding your regress diff: I don't think we want to land it as it is.

Ok.

> > The verifier lives in libcrypto/x509, so the regress test belongs in
> > there.

You are right, its the better place.  At least I want to send you a bug
report with concrete code to test.

> > We really need to come up with an extensible design that can check a
> > number of such cases (and ideally includes the bulk of your openssl/x509
> > regress tests). I don't want to add a directory for every bug in the
> > verifier or legacy verifier. As jsing already mentioned, I expect that
> > we want to commit the test certs so we don't need perl modules from
> > ports to run the regress. Then we want to add generating scripts and a
> > README that gives instructions on how to regenerate the certs if needed.
> > 
> > I would like to have one C program that runs all tests in a loop (or
> > perhaps one C program per family of regressions). It would be nice if
> > this C program could also be compiled against OpenSSL 1.1.1 so we can
> > easily check for differences of behavior (see x509/bettertls/Makefile
> > for an example that does this).  For your test program this just means:
> > don't access csc->blah, but use X509_STORE_CTX_get_blah(csc) instead.
> > 
> > Why does the test set TRUSTED_FIRST?

I just forget to remove the this line, from the original version.

> > The code also needs a bit of cleaning. There are a number of unchecked
> > return values, for example strdup and sk_*_push, and csc is leaked
> > after X509_verify_cert().
> > 
> > It would also be nice to run this test against the new verifier.

The test passes with the new verifier in current, but not in 6.8.

> Missed an obvious simplification.

The diff looks fine to me and it fixes our regressions.
I would give you an OK jan, fwiw.

Thanks,
Jan

> Index: x509/x509_vfy.c
> ===================================================================
> RCS file: /cvs/src/lib/libcrypto/x509/x509_vfy.c,v
> retrieving revision 1.85
> diff -u -p -r1.85 x509_vfy.c
> --- x509/x509_vfy.c   11 Feb 2021 04:56:43 -0000      1.85
> +++ x509/x509_vfy.c   24 Feb 2021 20:19:34 -0000
> @@ -240,12 +240,13 @@ x509_vfy_check_id(X509_STORE_CTX *ctx) {
>   * Oooooooh..
>   */
>  static int
> -X509_verify_cert_legacy_build_chain(X509_STORE_CTX *ctx, int *bad)
> +X509_verify_cert_legacy_build_chain(X509_STORE_CTX *ctx, int *bad, int 
> *out_ok)
>  {
>       X509 *x, *xtmp, *xtmp2, *chain_ss = NULL;
>       int bad_chain = 0;
>       X509_VERIFY_PARAM *param = ctx->param;
> -     int depth, i, ok = 0;
> +     int ok = 0, ret = 0;
> +     int depth, i;
>       int num, j, retry, trust;
>       int (*cb) (int xok, X509_STORE_CTX *xctx);
>       STACK_OF(X509) *sktmp = NULL;
> @@ -517,11 +518,15 @@ X509_verify_cert_legacy_build_chain(X509
>               if (!ok)
>                       goto end;
>       }
> +
> +     ret = 1;
>   end:
>       sk_X509_free(sktmp);
>       X509_free(chain_ss);
>       *bad = bad_chain;
> -     return ok;
> +     *out_ok = ok;
> +
> +     return ret;
>  }
>  
>  static int
> @@ -531,8 +536,7 @@ X509_verify_cert_legacy(X509_STORE_CTX *
>  
>       ctx->error = X509_V_OK; /* Initialize to OK */
>  
> -     ok = X509_verify_cert_legacy_build_chain(ctx, &bad_chain);
> -     if (!ok)
> +     if (!X509_verify_cert_legacy_build_chain(ctx, &bad_chain, &ok))
>               goto end;
>  
>       /* We have the chain complete: now we need to check its purpose */
> 

Reply via email to