On Mon, May 08, 2023 at 02:01:52PM +0200, Theo Buehler wrote:
> The diff below is based on a hint by beck and was discussed extensively
> with beck, claudio and job during and after m2k23. It results in a quite
> significant reduction of the runtime of an ordinary rpki-client run as
> usually done from cron.
> 
> One problem we're facing with the generally rather poor quality RFC 3779
> code in libcrypto is that its performance is abysmal. Flame graphs show
> a lot of time spent in addr_contains(). While there is some room for
> improvement in that function itself (the containment check for prefixes
> could be optimized quite a bit), we can avoid a lot of the most expensive
> checking of certificates with tons of resources close to the TA by using
> the partial chains flag.
> 
> More precisely, in the tree of already validated certs look for the first
> one that has no inherited RFC 3779 resources and use that as the trust
> anchor for our chains via the X509_V_FLAG_PARTIAL_CHAIN flag for the
> verifier. This way we can be sure that a leaf's delegated resources are
> properly covered and at the same time significantly shorten most paths
> validated. There is no downside to doing this since we have already
> validated the path from all certs in the auth tree to the root.
> 
> In my testing, this avoids 30-50% of overhead and works equally well
> with LibreSSL and OpenSSL 1.1.
> 
> I currently hang any_inherits off struct auth. It may be worthwhile to
> move that to struct cert and populate it in cert_parse_pre() in a later
> step.

OK claudio@
 
> Index: cert.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/cert.c,v
> retrieving revision 1.107
> diff -u -p -r1.107 cert.c
> --- cert.c    15 Apr 2023 00:39:08 -0000      1.107
> +++ cert.c    8 May 2023 11:04:30 -0000
> @@ -1092,6 +1092,7 @@ auth_insert(struct auth_tree *auths, str
>  
>       na->parent = parent;
>       na->cert = cert;
> +     na->any_inherits = x509_any_inherits(cert->x509);
>  
>       if (RB_INSERT(auth_tree, auths, na) != NULL)
>               err(1, "auth tree corrupted");
> Index: extern.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
> retrieving revision 1.180
> diff -u -p -r1.180 extern.h
> --- extern.h  27 Apr 2023 08:37:53 -0000      1.180
> +++ extern.h  8 May 2023 11:04:30 -0000
> @@ -454,6 +454,7 @@ struct auth {
>       RB_ENTRY(auth)   entry;
>       struct cert     *cert; /* owner information */
>       struct auth     *parent; /* pointer to parent or NULL for TA cert */
> +     int              any_inherits;
>  };
>  /*
>   * Tree of auth sorted by ski
> Index: validate.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v
> retrieving revision 1.59
> diff -u -p -r1.59 validate.c
> --- validate.c        27 Apr 2023 08:37:53 -0000      1.59
> +++ validate.c        8 May 2023 11:29:56 -0000
> @@ -332,25 +332,37 @@ valid_origin(const char *uri, const char
>  }
>  
>  /*
> - * Walk the certificate tree to the root and build a certificate
> - * chain from cert->x509. All certs in the tree are validated and
> - * can be loaded as trusted stack into the validator.
> + * Walk the tree of known valid CA certificates until we find a certificate 
> that
> + * doesn't inherit. Build a chain of intermediates and use the non-inheriting
> + * certificate as a trusted root by virtue of X509_V_FLAG_PARTIAL_CHAIN. The
> + * RFC 3779 path validation needs a non-inheriting trust root to ensure that
> + * all delegated resources are covered.
>   */
>  static void
> -build_chain(const struct auth *a, STACK_OF(X509) **chain)
> +build_chain(const struct auth *a, STACK_OF(X509) **intermediates,
> +    STACK_OF(X509) **root)
>  {
> -     *chain = NULL;
> +     *intermediates = NULL;
> +     *root = NULL;
>  
>       if (a == NULL)
>               return;
>  
> -     if ((*chain = sk_X509_new_null()) == NULL)
> +     if ((*intermediates = sk_X509_new_null()) == NULL)
> +             err(1, "sk_X509_new_null");
> +     if ((*root = sk_X509_new_null()) == NULL)
>               err(1, "sk_X509_new_null");
>       for (; a != NULL; a = a->parent) {
>               assert(a->cert->x509 != NULL);
> -             if (!sk_X509_push(*chain, a->cert->x509))
> +             if (!a->any_inherits) {
> +                     if (!sk_X509_push(*root, a->cert->x509))
> +                             errx(1, "sk_X509_push");
> +                     break;
> +             }
> +             if (!sk_X509_push(*intermediates, a->cert->x509))
>                       errx(1, "sk_X509_push");
>       }
> +     assert(sk_X509_num(*root) == 1);
>  }
>  
>  /*
> @@ -381,13 +393,13 @@ valid_x509(char *file, X509_STORE_CTX *s
>  {
>       X509_VERIFY_PARAM       *params;
>       ASN1_OBJECT             *cp_oid;
> -     STACK_OF(X509)          *chain;
> +     STACK_OF(X509)          *intermediates, *root;
>       STACK_OF(X509_CRL)      *crls = NULL;
>       unsigned long            flags;
>       int                      error;
>  
>       *errstr = NULL;
> -     build_chain(a, &chain);
> +     build_chain(a, &intermediates, &root);
>       build_crls(crl, &crls);
>  
>       assert(store_ctx != NULL);
> @@ -404,25 +416,33 @@ valid_x509(char *file, X509_STORE_CTX *s
>       X509_VERIFY_PARAM_set_time(params, evaluation_time);
>  
>       flags = X509_V_FLAG_CRL_CHECK;
> +     flags |= X509_V_FLAG_PARTIAL_CHAIN;
>       flags |= X509_V_FLAG_POLICY_CHECK;
>       flags |= X509_V_FLAG_EXPLICIT_POLICY;
>       flags |= X509_V_FLAG_INHIBIT_MAP;
>       X509_STORE_CTX_set_flags(store_ctx, flags);
>       X509_STORE_CTX_set_depth(store_ctx, MAX_CERT_DEPTH);
> -     X509_STORE_CTX_set0_trusted_stack(store_ctx, chain);
> +     /*
> +      * See the comment above build_chain() for details on what's happening
> +      * here. The nomenclature in this API is dubious and poorly documented.
> +      */
> +     X509_STORE_CTX_set0_untrusted(store_ctx, intermediates);
> +     X509_STORE_CTX_set0_trusted_stack(store_ctx, root);
>       X509_STORE_CTX_set0_crls(store_ctx, crls);
>  
>       if (X509_verify_cert(store_ctx) <= 0) {
>               error = X509_STORE_CTX_get_error(store_ctx);
>               *errstr = X509_verify_cert_error_string(error);
>               X509_STORE_CTX_cleanup(store_ctx);
> -             sk_X509_free(chain);
> +             sk_X509_free(intermediates);
> +             sk_X509_free(root);
>               sk_X509_CRL_free(crls);
>               return 0;
>       }
>  
>       X509_STORE_CTX_cleanup(store_ctx);
> -     sk_X509_free(chain);
> +     sk_X509_free(intermediates);
> +     sk_X509_free(root);
>       sk_X509_CRL_free(crls);
>       return 1;
>  }
> 

-- 
:wq Claudio

Reply via email to