From 4f2938160a2631bf0980365ef58e1ca282f63c34 Mon Sep 17 00:00:00 2001 From: tb Date: Sat, 13 Jan 2024 11:08:39 +0000 Subject: [PATCH] Reimplement {EVP_CIPHER,EVP_MD,OBJ_NAME}_do_all{,_sorted}(3) This implements the do_all API by simple loops over the tables of digests and ciphers. Since some ciphers are only available on some platforms, we need to skip them if necessary. We use loops in each of the functions rather the convoluted way of reducing some of the loops to others. Since the tables are sorted, as ensured by regress, both do_all() and do_all_sorted() walk the lists in order. In particular, we no longer need to allocate to be able to sort hash tables by name on the fly in a void function that may end up doing nothing because allocation failed. We still need to do an unchecked OPENSSL_init_crypto() call. But that's what prayer and clean living are there for (as beck put it). The OBJ_NAME API is completely misnamed. It has little to do with objects and a lot to do with EVP. Therefore we implement what will remain from its saner replacement in the evp directory, i.e., evp_names.c. ok jsing --- lib/libcrypto/evp/evp_names.c | 162 +++++++++++++++++++++++++++++++- lib/libcrypto/evp/names.c | 93 +----------------- lib/libcrypto/objects/o_names.c | 81 +--------------- 3 files changed, 161 insertions(+), 175 deletions(-) diff --git a/lib/libcrypto/evp/evp_names.c b/lib/libcrypto/evp/evp_names.c index fbd84711f5f..b5d3b95b453 100644 --- a/lib/libcrypto/evp/evp_names.c +++ b/lib/libcrypto/evp/evp_names.c @@ -1,4 +1,4 @@ -/* $OpenBSD: evp_names.c,v 1.2 2024/01/13 11:00:09 tb Exp $ */ +/* $OpenBSD: evp_names.c,v 1.3 2024/01/13 11:08:39 tb Exp $ */ /* * Copyright (c) 2023 Theo Buehler * @@ -41,7 +41,7 @@ struct digest_name { * regress/lib/libcrypto/evp/evp_test.c checks that. */ -const struct cipher_name cipher_names[] = { +static const struct cipher_name cipher_names[] = { #ifndef OPENSSL_NO_AES { .name = SN_aes_128_cbc, @@ -1099,7 +1099,7 @@ const struct cipher_name cipher_names[] = { * regresss/lib/libcrypto/evp/evp_test.c checks that. */ -const struct digest_name digest_names[] = { +static const struct digest_name digest_names[] = { #ifndef OPENSSL_NO_GOST { .name = LN_id_Gost28147_89_MAC, @@ -1559,3 +1559,159 @@ const struct digest_name digest_names[] = { }; #define N_DIGEST_NAMES (sizeof(digest_names) / sizeof(digest_names[0])) + +void +EVP_CIPHER_do_all_sorted(void (*fn)(const EVP_CIPHER *, const char *, + const char *, void *), void *arg) +{ + size_t i; + + /* Prayer and clean living lets you ignore errors, OpenSSL style. */ + (void)OPENSSL_init_crypto(0, NULL); + + for (i = 0; i < N_CIPHER_NAMES; i++) { + const struct cipher_name *cipher = &cipher_names[i]; + const EVP_CIPHER *evp_cipher; + + if ((evp_cipher = cipher->cipher()) == NULL) + continue; + + if (cipher->alias != NULL) + fn(NULL, cipher->name, cipher->alias, arg); + else + fn(evp_cipher, cipher->name, NULL, arg); + } +} + +void +EVP_CIPHER_do_all(void (*fn)(const EVP_CIPHER *, const char *, const char *, + void *), void *arg) +{ + EVP_CIPHER_do_all_sorted(fn, arg); +} + +void +EVP_MD_do_all_sorted(void (*fn)(const EVP_MD *, const char *, const char *, + void *), void *arg) +{ + size_t i; + + /* Prayer and clean living lets you ignore errors, OpenSSL style. */ + (void)OPENSSL_init_crypto(0, NULL); + + for (i = 0; i < N_DIGEST_NAMES; i++) { + const struct digest_name *digest = &digest_names[i]; + const EVP_MD *evp_md; + + if ((evp_md = digest->digest()) == NULL) + continue; + + if (digest->alias != NULL) + fn(NULL, digest->name, digest->alias, arg); + else + fn(evp_md, digest->name, NULL, arg); + } +} + +void +EVP_MD_do_all(void (*fn)(const EVP_MD *, const char *, const char *, void *), + void *arg) +{ + EVP_MD_do_all_sorted(fn, arg); +} + +/* + * The OBJ_NAME API is completely misnamed. It has little to do with objects + * and a lot to do with EVP. Therefore we implement a saner replacement for + * the part of the old madness that we need to keep in the evp directory. + */ + +static int +OBJ_NAME_from_cipher_name(OBJ_NAME *obj_name, const struct cipher_name *cipher) +{ + const EVP_CIPHER *evp_cipher; + + if ((evp_cipher = cipher->cipher()) == NULL) + return 0; + + obj_name->type = OBJ_NAME_TYPE_CIPHER_METH; + obj_name->name = cipher->name; + if (cipher->alias != NULL) { + obj_name->alias = OBJ_NAME_ALIAS; + obj_name->data = cipher->alias; + } else { + obj_name->alias = 0; + obj_name->data = (const char *)evp_cipher; + } + + return 1; +} + +static void +OBJ_NAME_do_all_ciphers(void (*fn)(const OBJ_NAME *, void *), void *arg) +{ + size_t i; + + for (i = 0; i < N_CIPHER_NAMES; i++) { + const struct cipher_name *cipher = &cipher_names[i]; + OBJ_NAME name; + + if (OBJ_NAME_from_cipher_name(&name, cipher)) + fn(&name, arg); + } +} + +static int +OBJ_NAME_from_digest_name(OBJ_NAME *obj_name, const struct digest_name *digest) +{ + const EVP_MD *evp_md; + + if ((evp_md = digest->digest()) == NULL) + return 0; + + obj_name->type = OBJ_NAME_TYPE_MD_METH; + obj_name->name = digest->name; + if (digest->alias != NULL) { + obj_name->alias = OBJ_NAME_ALIAS; + obj_name->data = digest->alias; + } else { + obj_name->alias = 0; + obj_name->data = (const char *)evp_md; + } + + return 1; +} + +static void +OBJ_NAME_do_all_digests(void (*fn)(const OBJ_NAME *, void *), void *arg) +{ + size_t i; + + for (i = 0; i < N_DIGEST_NAMES; i++) { + const struct digest_name *digest = &digest_names[i]; + OBJ_NAME name; + + if (OBJ_NAME_from_digest_name(&name, digest)) + fn(&name, arg); + } +} + +void +OBJ_NAME_do_all_sorted(int type, void (*fn)(const OBJ_NAME *, void *), void *arg) +{ + /* Prayer and clean living lets you ignore errors, OpenSSL style. */ + (void)OPENSSL_init_crypto(0, NULL); + + if (type == OBJ_NAME_TYPE_CIPHER_METH) + OBJ_NAME_do_all_ciphers(fn, arg); + if (type == OBJ_NAME_TYPE_MD_METH) + OBJ_NAME_do_all_digests(fn, arg); +} +LCRYPTO_ALIAS(OBJ_NAME_do_all_sorted); + +void +OBJ_NAME_do_all(int type, void (*fn)(const OBJ_NAME *, void *), void *arg) +{ + OBJ_NAME_do_all_sorted(type, fn, arg); +} +LCRYPTO_ALIAS(OBJ_NAME_do_all); diff --git a/lib/libcrypto/evp/names.c b/lib/libcrypto/evp/names.c index a96301ed56b..7f5b4550885 100644 --- a/lib/libcrypto/evp/names.c +++ b/lib/libcrypto/evp/names.c @@ -1,4 +1,4 @@ -/* $OpenBSD: names.c,v 1.22 2023/12/15 14:22:10 tb Exp $ */ +/* $OpenBSD: names.c,v 1.23 2024/01/13 11:08:39 tb Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -146,94 +146,3 @@ EVP_cleanup(void) OBJ_cleanup(); } } - -struct doall_cipher { - void *arg; - void (*fn)(const EVP_CIPHER *ciph, const char *from, const char *to, - void *arg); -}; - -static void -do_all_cipher_fn(const OBJ_NAME *nm, void *arg) -{ - struct doall_cipher *dc = arg; - - if (nm->alias) - dc->fn(NULL, nm->name, nm->data, dc->arg); - else - dc->fn((const EVP_CIPHER *)nm->data, nm->name, NULL, dc->arg); -} - -void -EVP_CIPHER_do_all(void (*fn)(const EVP_CIPHER *ciph, const char *from, - const char *to, void *x), void *arg) -{ - struct doall_cipher dc; - - /* Prayer and clean living lets you ignore errors, OpenSSL style */ - (void) OPENSSL_init_crypto(0, NULL); - - dc.fn = fn; - dc.arg = arg; - OBJ_NAME_do_all(OBJ_NAME_TYPE_CIPHER_METH, do_all_cipher_fn, &dc); -} - -void -EVP_CIPHER_do_all_sorted(void (*fn)(const EVP_CIPHER *ciph, const char *from, - const char *to, void *x), void *arg) -{ - struct doall_cipher dc; - - /* Prayer and clean living lets you ignore errors, OpenSSL style */ - (void) OPENSSL_init_crypto(0, NULL); - - dc.fn = fn; - dc.arg = arg; - OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, - do_all_cipher_fn, &dc); -} - -struct doall_md { - void *arg; - void (*fn)(const EVP_MD *ciph, const char *from, const char *to, - void *arg); -}; - -static void -do_all_md_fn(const OBJ_NAME *nm, void *arg) -{ - struct doall_md *dc = arg; - - if (nm->alias) - dc->fn(NULL, nm->name, nm->data, dc->arg); - else - dc->fn((const EVP_MD *)nm->data, nm->name, NULL, dc->arg); -} - -void -EVP_MD_do_all(void (*fn)(const EVP_MD *md, const char *from, const char *to, - void *x), void *arg) -{ - struct doall_md dc; - - /* Prayer and clean living lets you ignore errors, OpenSSL style */ - (void) OPENSSL_init_crypto(0, NULL); - - dc.fn = fn; - dc.arg = arg; - OBJ_NAME_do_all(OBJ_NAME_TYPE_MD_METH, do_all_md_fn, &dc); -} - -void -EVP_MD_do_all_sorted(void (*fn)(const EVP_MD *md, - const char *from, const char *to, void *x), void *arg) -{ - struct doall_md dc; - - /* Prayer and clean living lets you ignore errors, OpenSSL style */ - (void) OPENSSL_init_crypto(0, NULL); - - dc.fn = fn; - dc.arg = arg; - OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_MD_METH, do_all_md_fn, &dc); -} diff --git a/lib/libcrypto/objects/o_names.c b/lib/libcrypto/objects/o_names.c index 48b95d6767a..1007c5e23a1 100644 --- a/lib/libcrypto/objects/o_names.c +++ b/lib/libcrypto/objects/o_names.c @@ -1,4 +1,4 @@ -/* $OpenBSD: o_names.c,v 1.24 2023/07/08 12:27:51 beck Exp $ */ +/* $OpenBSD: o_names.c,v 1.25 2024/01/13 11:08:39 tb Exp $ */ #include #include #include @@ -240,85 +240,6 @@ OBJ_NAME_remove(const char *name, int type) } LCRYPTO_ALIAS(OBJ_NAME_remove); -struct doall { - int type; - void (*fn)(const OBJ_NAME *, void *arg); - void *arg; -}; - -static void -do_all_fn_doall_arg(const OBJ_NAME *name, struct doall *d) -{ - if (name->type == d->type) - d->fn(name, d->arg); -} - -static IMPLEMENT_LHASH_DOALL_ARG_FN(do_all_fn, const OBJ_NAME, struct doall) - -void -OBJ_NAME_do_all(int type, void (*fn)(const OBJ_NAME *, void *arg), void *arg) -{ - struct doall d; - - d.type = type; - d.fn = fn; - d.arg = arg; - - lh_OBJ_NAME_doall_arg(names_lh, LHASH_DOALL_ARG_FN(do_all_fn), - struct doall, &d); -} -LCRYPTO_ALIAS(OBJ_NAME_do_all); - -struct doall_sorted { - int type; - int n; - const OBJ_NAME **names; -}; - -static void -do_all_sorted_fn(const OBJ_NAME *name, void *d_) -{ - struct doall_sorted *d = d_; - - if (name->type != d->type) - return; - - d->names[d->n++] = name; -} - -static int -do_all_sorted_cmp(const void *n1_, const void *n2_) -{ - const OBJ_NAME * const *n1 = n1_; - const OBJ_NAME * const *n2 = n2_; - - return strcmp((*n1)->name, (*n2)->name); -} - -void -OBJ_NAME_do_all_sorted(int type, void (*fn)(const OBJ_NAME *, void *arg), - void *arg) -{ - struct doall_sorted d; - int n; - - d.type = type; - d.names = reallocarray(NULL, lh_OBJ_NAME_num_items(names_lh), - sizeof *d.names); - d.n = 0; - if (d.names != NULL) { - OBJ_NAME_do_all(type, do_all_sorted_fn, &d); - - qsort((void *)d.names, d.n, sizeof *d.names, do_all_sorted_cmp); - - for (n = 0; n < d.n; ++n) - fn(d.names[n], arg); - - free(d.names); - } -} -LCRYPTO_ALIAS(OBJ_NAME_do_all_sorted); - static int free_type; static void -- 2.20.1