x509: sort stacks before finds

x509_trust.c, x509_vpm.c and v3_lib.c don't have a lock for their sorts.
This is no worse than the existing code which sorted silently without locks.

Addition is quadratic time in by_dir.c and v3_purp.c.  However, this
is an improvement over the older O(n^2 log n) code where each find also
sorted the stack.  Also note that v3_purp.c is limited to a maximum of
10 items, so quadratic behaviour isn't terrible.

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Todd Short <todd.short@me.com>
(Merged from https://github.com/openssl/openssl/pull/20842)
This commit is contained in:
Pauli 2023-04-27 10:58:50 +10:00
parent 07f9c81d20
commit efe0222f5c
7 changed files with 24 additions and 0 deletions

View File

@ -348,6 +348,9 @@ static int get_cert_by_subject_ex(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
/* /*
* we have added it to the cache so now pull it out again * we have added it to the cache so now pull it out again
*
* Note: quadratic time find here since the objects won't generally be
* sorted and sorting the would result in O(n^2 log n) complexity.
*/ */
X509_STORE_lock(xl->store_ctx); X509_STORE_lock(xl->store_ctx);
j = sk_X509_OBJECT_find(xl->store_ctx->objs, &stmp); j = sk_X509_OBJECT_find(xl->store_ctx->objs, &stmp);
@ -417,6 +420,13 @@ static int get_cert_by_subject_ex(X509_LOOKUP *xl, X509_LOOKUP_TYPE type,
} }
} }
finish: finish:
/* If we changed anything, resort the objects for faster lookup */
if (!sk_X509_OBJECT_is_sorted(xl->store_ctx->objs)) {
X509_STORE_lock(xl->store_ctx);
sk_X509_OBJECT_sort(xl->store_ctx->objs);
X509_STORE_unlock(xl->store_ctx);
}
BUF_MEM_free(b); BUF_MEM_free(b);
return ok; return ok;
} }

View File

@ -63,6 +63,8 @@ static int policy_cache_create(X509 *x,
} }
data = NULL; data = NULL;
} }
/* Sort so we can find more quickly */
sk_X509_POLICY_DATA_sort(cache->data);
ret = 1; ret = 1;
bad_policy: bad_policy:

View File

@ -689,6 +689,7 @@ int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
if ((calc_ret = tree_calculate_authority_set(tree, &auth_nodes)) == 0) if ((calc_ret = tree_calculate_authority_set(tree, &auth_nodes)) == 0)
goto error; goto error;
sk_X509_POLICY_NODE_sort(auth_nodes);
ret = tree_calculate_user_set(tree, policy_oids, auth_nodes); ret = tree_calculate_user_set(tree, policy_oids, auth_nodes);
if (calc_ret == TREE_CALC_OK_DOFREE) if (calc_ret == TREE_CALC_OK_DOFREE)
sk_X509_POLICY_NODE_free(auth_nodes); sk_X509_POLICY_NODE_free(auth_nodes);

View File

@ -1176,6 +1176,8 @@ int X509v3_addr_subset(IPAddrBlocks *a, IPAddrBlocks *b)
if (b == NULL || X509v3_addr_inherits(a) || X509v3_addr_inherits(b)) if (b == NULL || X509v3_addr_inherits(a) || X509v3_addr_inherits(b))
return 0; return 0;
(void)sk_IPAddressFamily_set_cmp_func(b, IPAddressFamily_cmp); (void)sk_IPAddressFamily_set_cmp_func(b, IPAddressFamily_cmp);
sk_IPAddressFamily_sort(b);
/* Could sort a here too and get O(|a|) running time instead of O(|a| ln |b|) */
for (i = 0; i < sk_IPAddressFamily_num(a); i++) { for (i = 0; i < sk_IPAddressFamily_num(a); i++) {
IPAddressFamily *fa = sk_IPAddressFamily_value(a, i); IPAddressFamily *fa = sk_IPAddressFamily_value(a, i);
int j = sk_IPAddressFamily_find(b, fa); int j = sk_IPAddressFamily_find(b, fa);
@ -1257,6 +1259,7 @@ static int addr_validate_path_internal(X509_STORE_CTX *ctx,
ctx->error = X509_V_ERR_OUT_OF_MEM; ctx->error = X509_V_ERR_OUT_OF_MEM;
goto done; goto done;
} }
sk_IPAddressFamily_sort(child);
/* /*
* Now walk up the chain. No cert may list resources that its * Now walk up the chain. No cert may list resources that its
@ -1282,6 +1285,7 @@ static int addr_validate_path_internal(X509_STORE_CTX *ctx,
} }
(void)sk_IPAddressFamily_set_cmp_func(x->rfc3779_addr, (void)sk_IPAddressFamily_set_cmp_func(x->rfc3779_addr,
IPAddressFamily_cmp); IPAddressFamily_cmp);
sk_IPAddressFamily_sort(x->rfc3779_addr);
for (j = 0; j < sk_IPAddressFamily_num(child); j++) { for (j = 0; j < sk_IPAddressFamily_num(child); j++) {
IPAddressFamily *fc = sk_IPAddressFamily_value(child, j); IPAddressFamily *fc = sk_IPAddressFamily_value(child, j);
int k = sk_IPAddressFamily_find(x->rfc3779_addr, fc); int k = sk_IPAddressFamily_find(x->rfc3779_addr, fc);

View File

@ -63,7 +63,10 @@ const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid)
return *ret; return *ret;
if (!ext_list) if (!ext_list)
return NULL; return NULL;
/* Ideally, this would be done under a lock */
sk_X509V3_EXT_METHOD_sort(ext_list);
idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp); idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp);
/* A failure to locate the item is handled by the value method */
return sk_X509V3_EXT_METHOD_value(ext_list, idx); return sk_X509V3_EXT_METHOD_value(ext_list, idx);
} }

View File

@ -105,6 +105,8 @@ int X509_TRUST_get_by_id(int id)
if (trtable == NULL) if (trtable == NULL)
return -1; return -1;
tmp.trust = id; tmp.trust = id;
/* Ideally, this would be done under lock */
sk_X509_TRUST_sort(trtable);
idx = sk_X509_TRUST_find(trtable, &tmp); idx = sk_X509_TRUST_find(trtable, &tmp);
if (idx < 0) if (idx < 0)
return -1; return -1;

View File

@ -635,6 +635,8 @@ const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name)
pm.name = (char *)name; pm.name = (char *)name;
if (param_table != NULL) { if (param_table != NULL) {
/* Ideally, this would be done under a lock */
sk_X509_VERIFY_PARAM_sort(param_table);
idx = sk_X509_VERIFY_PARAM_find(param_table, &pm); idx = sk_X509_VERIFY_PARAM_find(param_table, &pm);
if (idx >= 0) if (idx >= 0)
return sk_X509_VERIFY_PARAM_value(param_table, idx); return sk_X509_VERIFY_PARAM_value(param_table, idx);