Hi,

We have developed a patch to improve performance of SSL_load_client_CA_file.
Given a CA file containing many CA certs, it took a long time to check
duplicates because, inside SSL_load_client_CA_file, sk_X509_NAME_find
executes qsort and bsearch for every cert.
The patch introduces hash to check duplicates.  This resulted in 300x
speed up in our tests using CA file containing 3742 certs. Specifically,
it took 940ms; after the patch applied, it now takes only 3.3ms.
The attached patch can apply to openssl 1.0.1i cleanly.

Thanks,
Toshikuni Fukaya

diff -ur openssl-1.0.1i/ssl/ssl_cert.c openssl-1.0.1i-mod/ssl/ssl_cert.c
--- openssl-1.0.1i/ssl/ssl_cert.c       2014-08-07 06:10:56.000000000 +0900
+++ openssl-1.0.1i-mod/ssl/ssl_cert.c   2014-08-21 16:22:54.510854510 +0900
@@ -131,6 +131,7 @@
 #endif
 #include <openssl/bn.h>
 #include "ssl_locl.h"
+#include <openssl/lhash.h>
 
 int SSL_get_ex_data_X509_STORE_CTX_idx(void)
        {
@@ -660,6 +661,10 @@
        return(X509_NAME_cmp(*a,*b));
        }
 
+DECLARE_LHASH_OF(X509_NAME);
+static IMPLEMENT_LHASH_HASH_FN(X509_NAME, X509_NAME)
+static IMPLEMENT_LHASH_COMP_FN(X509_NAME, X509_NAME)
+
 #ifndef OPENSSL_NO_STDIO
 /*!
  * Load CA certs from a file into a ::STACK. Note that it is somewhat misnamed;
@@ -674,13 +679,14 @@
        BIO *in;
        X509 *x=NULL;
        X509_NAME *xn=NULL;
-       STACK_OF(X509_NAME) *ret = NULL,*sk;
+       STACK_OF(X509_NAME) *ret = NULL;
+       LHASH_OF(X509_NAME) *name_hash = NULL;
 
-       sk=sk_X509_NAME_new(xname_cmp);
+       name_hash = LHM_lh_new(X509_NAME, X509_NAME);
 
        in=BIO_new(BIO_s_file_internal());
 
-       if ((sk == NULL) || (in == NULL))
+       if ((name_hash == NULL) || (in == NULL))
                {
                SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE,ERR_R_MALLOC_FAILURE);
                goto err;
@@ -706,11 +712,11 @@
                /* check for duplicates */
                xn=X509_NAME_dup(xn);
                if (xn == NULL) goto err;
-               if (sk_X509_NAME_find(sk,xn) >= 0)
+               if (LHM_lh_retrieve(X509_NAME, name_hash, xn) != NULL)
                        X509_NAME_free(xn);
                else
                        {
-                       sk_X509_NAME_push(sk,xn);
+                       LHM_lh_insert(X509_NAME, name_hash, xn);
                        sk_X509_NAME_push(ret,xn);
                        }
                }
@@ -721,7 +727,7 @@
                if (ret != NULL) sk_X509_NAME_pop_free(ret,X509_NAME_free);
                ret=NULL;
                }
-       if (sk != NULL) sk_X509_NAME_free(sk);
+       if (name_hash != NULL) LHM_lh_free(X509_NAME, name_hash);
        if (in != NULL) BIO_free(in);
        if (x != NULL) X509_free(x);
        if (ret != NULL)

Reply via email to