Reimplement {EVP_CIPHER,EVP_MD,OBJ_NAME}_do_all{,_sorted}(3)
authortb <tb@openbsd.org>
Sat, 13 Jan 2024 11:08:39 +0000 (11:08 +0000)
committertb <tb@openbsd.org>
Sat, 13 Jan 2024 11:08:39 +0000 (11:08 +0000)
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
lib/libcrypto/evp/names.c
lib/libcrypto/objects/o_names.c

index fbd8471..b5d3b95 100644 (file)
@@ -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 <tb@openbsd.org>
  *
@@ -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);
index a96301e..7f5b455 100644 (file)
@@ -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);
-}
index 48b95d6..1007c5e 100644 (file)
@@ -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 <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -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