[openssl] master update

Richard Levitte levitte at openssl.org
Mon Jul 15 05:01:35 UTC 2019


The branch master has been updated
       via  b6c97eee78c9ab646137772497b65e99124970db (commit)
       via  9af71317f9e5708dada7c1a660d862741945c436 (commit)
       via  23e34aa213a2e8003092436ab6f5dae68283e698 (commit)
       via  148609c62734f2068303ffa90f4ff8004478337e (commit)
       via  7da6cc6ccb1035fdc14ab1fc54321ad30bca1e58 (commit)
       via  f4ae5ba4b7d07fc9df4acbb7741aea75a1c584b0 (commit)
       via  ed45c999114e412edbd0018c435ae91e06625358 (commit)
       via  c1798afbe37f9a98278050c3437b715c16ce0e2b (commit)
       via  e3cbccc5bbe18930c1d98b64abb505aad221c18d (commit)
       via  753149d97f8474ff8745a66175b8e4a19fe50743 (commit)
       via  4b62b8ed4989bb6767a38ae813495ba62215c25b (commit)
      from  a161738a708b5e284a4714edc0c976606ea7cb26 (commit)


- Log -----------------------------------------------------------------
commit b6c97eee78c9ab646137772497b65e99124970db
Author: Richard Levitte <levitte at openssl.org>
Date:   Sat Jul 13 07:04:01 2019 +0200

    Re-implement the cipher and digest listings for 'openssl list'
    
    They now display both legacy and provided algorithms.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9340)

commit 9af71317f9e5708dada7c1a660d862741945c436
Author: Richard Levitte <levitte at openssl.org>
Date:   Sat Jul 13 07:02:54 2019 +0200

    Add EVP_CIPHER_do_all_ex() and EVP_MD_do_all_ex()
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9340)

commit 23e34aa213a2e8003092436ab6f5dae68283e698
Author: Richard Levitte <levitte at openssl.org>
Date:   Sat Jul 13 06:53:44 2019 +0200

    Add internal function evp_generic_do_all()
    
    This function is used to traverse all algorithm implementations for a
    given operation type, and execute the given function for each of them.
    
    For each algorithm implementation, a method is created and passed to
    the given function, and then freed after that function's return.  If
    the caller wishes to keep the method for longer, they must call the
    appropriate up_ref function on the method, and they must also make
    sure to free the passed methods at some point.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9340)

commit 148609c62734f2068303ffa90f4ff8004478337e
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Jul 10 23:14:03 2019 +0200

    Refactor ossl_method_construct() in terms of ossl_algorithm_do_all()
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9340)

commit 7da6cc6ccb1035fdc14ab1fc54321ad30bca1e58
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Jul 10 23:11:27 2019 +0200

    Add internal function ossl_algorithm_do_all()
    
    This function is used to traverse all the implementations provided by
    one provider, or all implementation for a specific operation across
    all loaded providers, or both, and execute a given function for each
    occurence.
    
    This will be used by ossl_method_construct(), but also by information
    processing functions.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9340)

commit f4ae5ba4b7d07fc9df4acbb7741aea75a1c584b0
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Jul 10 23:00:22 2019 +0200

    Add OSSL_PROVIDER_name()
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9340)

commit ed45c999114e412edbd0018c435ae91e06625358
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Jul 10 22:59:07 2019 +0200

    Add EVP_MD_provider() and EVP_CIPHER_provider()
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9340)

commit c1798afbe37f9a98278050c3437b715c16ce0e2b
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Jul 10 22:24:00 2019 +0200

    Re-implement EVP_MD_name() and EVP_CIPHER_name() as functions
    
    They will do the same as usual for non-provider algorithms
    implementations, but can handle provider implementations as well.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9340)

commit e3cbccc5bbe18930c1d98b64abb505aad221c18d
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Jul 10 22:22:16 2019 +0200

    Add a mechnism to save the name of fetched methods
    
    This will be useful for information display, as well as for code that
    want to check the name of an algorithm.  This can eventually replace
    all NID checks.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9340)

commit 753149d97f8474ff8745a66175b8e4a19fe50743
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Jul 10 20:25:03 2019 +0200

    Move the code for 'openssl list' to its own translation unit.
    
    That makes it easier to work with than going through apps/openssl.c
    This also moves the implementation of calculate_columns() and makes it
    generally accessible.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9340)

commit 4b62b8ed4989bb6767a38ae813495ba62215c25b
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Jul 10 20:19:36 2019 +0200

    Refactor apps/progs.* to be generate with 'make update'
    
    This makes for a cleaner apps/progs.h as well as as cleaner
    apps/build.info.
    
    We also break out the type declarations to apps/include/function.h
    
    apps/progs.c and apps/progs.h are NOT regenerated when 'apps' is
    disabled.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/9340)

-----------------------------------------------------------------------

Summary of changes:
 .gitignore                                  |   1 -
 Configurations/unix-Makefile.tmpl           |   6 +
 apps/build.info                             |  11 +-
 apps/columns.c                              |  27 ++
 apps/include/function.h                     |  40 ++
 apps/list.c                                 | 578 ++++++++++++++++++++++++++++
 apps/openssl.c                              | 513 +-----------------------
 apps/progs.c                                | 398 +++++++++++++++++++
 apps/progs.h                                | 119 ++++++
 apps/progs.pl                               | 250 ++++++------
 crypto/build.info                           |   3 +-
 crypto/core_algorithm.c                     |  76 ++++
 crypto/core_fetch.c                         |  78 ++--
 crypto/evp/cmeth_lib.c                      |   1 +
 crypto/evp/digest.c                         |  13 +-
 crypto/evp/evp_enc.c                        |  14 +-
 crypto/evp/evp_fetch.c                      |  47 ++-
 crypto/evp/evp_lib.c                        |  33 ++
 crypto/evp/evp_locl.h                       |  10 +-
 crypto/include/internal/evp_int.h           |   2 +
 crypto/provider.c                           |   5 +
 doc/internal/man3/ossl_algorithm_do_all.pod |  63 +++
 doc/man3/EVP_DigestInit.pod                 |  21 +-
 doc/man3/EVP_EncryptInit.pod                |  11 +
 doc/man3/OSSL_PROVIDER.pod                  |   4 +
 include/internal/core.h                     |   7 +
 include/openssl/core_numbers.h              |   3 +
 include/openssl/evp.h                       |  14 +-
 include/openssl/provider.h                  |   3 +
 util/libcrypto.num                          |   7 +
 30 files changed, 1661 insertions(+), 697 deletions(-)
 create mode 100644 apps/columns.c
 create mode 100644 apps/include/function.h
 create mode 100644 apps/list.c
 create mode 100644 apps/progs.c
 create mode 100644 apps/progs.h
 create mode 100644 crypto/core_algorithm.c
 create mode 100644 doc/internal/man3/ossl_algorithm_do_all.pod

diff --git a/.gitignore b/.gitignore
index b32122c..fb08a3c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,7 +26,6 @@ Makefile
 
 # Auto generated headers
 /crypto/buildinf.h
-/apps/progs.h
 /crypto/include/internal/*_conf.h
 /openssl/include/opensslconf.h
 /util/domd
diff --git a/Configurations/unix-Makefile.tmpl b/Configurations/unix-Makefile.tmpl
index 52eeaa9..9309f40 100644
--- a/Configurations/unix-Makefile.tmpl
+++ b/Configurations/unix-Makefile.tmpl
@@ -742,6 +742,12 @@ lint:
 generate_apps:
 	( cd $(SRCDIR); $(PERL) VMS/VMSify-conf.pl \
 				< apps/openssl.cnf > apps/openssl-vms.cnf )
+	@ : {- output_off() if $disabled{apps}; "" -}
+	( b=`pwd`; cd $(SRCDIR); \
+	  $(PERL) -I$$b apps/progs.pl -H $(APPS_OPENSSL) > apps/progs.h )
+	( b=`pwd`; cd $(SRCDIR); \
+	  $(PERL) -I$$b apps/progs.pl -C $(APPS_OPENSSL) > apps/progs.c )
+	@ : {- output_on() if $disabled{apps}; "" -}
 
 generate_crypto_bn:
 	( cd $(SRCDIR); $(PERL) crypto/bn/bn_prime.pl > crypto/bn/bn_prime.h )
diff --git a/apps/build.info b/apps/build.info
index 3b4ea25..2a7317a 100644
--- a/apps/build.info
+++ b/apps/build.info
@@ -20,18 +20,18 @@ ENDIF
 # We need the perl variable for the DEPEND generator further down.
 $OPENSSLSRC={-
    our @opensslsrc =
-       qw(openssl.c
+       qw(openssl.c progs.c
           asn1pars.c ca.c ciphers.c cms.c crl.c crl2p7.c dgst.c dhparam.c
           dsa.c dsaparam.c ec.c ecparam.c enc.c engine.c errstr.c gendsa.c
           genpkey.c genrsa.c kdf.c mac.c nseq.c ocsp.c passwd.c pkcs12.c pkcs7.c
           pkcs8.c pkey.c pkeyparam.c pkeyutl.c prime.c rand.c req.c rsa.c
           rsautl.c s_client.c s_server.c s_time.c sess_id.c smime.c speed.c
           spkac.c srp.c ts.c verify.c version.c x509.c rehash.c storeutl.c
-          info.c);
+          list.c info.c);
    join(' ', @opensslsrc); -}
 # Source for libapps
 $LIBAPPSSRC=apps.c apps_ui.c opt.c fmt.c s_cb.c s_socket.c app_rand.c \
-        bf_prefix.c
+        bf_prefix.c columns.c
 
 IF[{- !$disabled{apps} -}]
   LIBS{noinst}=libapps.a
@@ -48,11 +48,6 @@ IF[{- !$disabled{apps} -}]
     SOURCE[openssl]=openssl.rc
   ENDIF
 
-  {- join("\n  ", map { (my $x = $_) =~ s|\.c$|.o|; "DEPEND[$x]=progs.h" }
-                  @opensslsrc) -}
-  GENERATE[progs.h]=progs.pl $(APPS_OPENSSL)
-  DEPEND[progs.h]=../configdata.pm
-
   SCRIPTS{misc}=CA.pl
   SOURCE[CA.pl]=CA.pl.in
   # linkname tells build files that a symbolic link or copy of this script
diff --git a/apps/columns.c b/apps/columns.c
new file mode 100644
index 0000000..aa58fe1
--- /dev/null
+++ b/apps/columns.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017-2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include "apps.h"
+#include "function.h"
+
+void calculate_columns(FUNCTION *functions, DISPLAY_COLUMNS *dc)
+{
+    FUNCTION *f;
+    int len, maxlen = 0;
+
+    for (f = functions; f->name != NULL; ++f)
+        if (f->type == FT_general || f->type == FT_md || f->type == FT_cipher)
+            if ((len = strlen(f->name)) > maxlen)
+                maxlen = len;
+
+    dc->width = maxlen + 2;
+    dc->columns = (80 - 1) / dc->width;
+}
+
diff --git a/apps/include/function.h b/apps/include/function.h
new file mode 100644
index 0000000..4125979
--- /dev/null
+++ b/apps/include/function.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef APPS_FUNCTION_H
+# define APPS_FUNCTION_H
+
+# include <openssl/lhash.h>
+# include "opt.h"
+
+typedef enum FUNC_TYPE {
+    FT_none, FT_general, FT_md, FT_cipher, FT_pkey,
+    FT_md_alg, FT_cipher_alg
+} FUNC_TYPE;
+
+typedef struct function_st {
+    FUNC_TYPE type;
+    const char *name;
+    int (*func)(int argc, char *argv[]);
+    const OPTIONS *help;
+} FUNCTION;
+
+DEFINE_LHASH_OF(FUNCTION);
+
+/* Structure to hold the number of columns to be displayed and the
+ * field width used to display them.
+ */
+typedef struct {
+    int columns;
+    int width;
+} DISPLAY_COLUMNS;
+
+void calculate_columns(FUNCTION *functions, DISPLAY_COLUMNS *dc);
+
+#endif
diff --git a/apps/list.c b/apps/list.c
new file mode 100644
index 0000000..56fd724
--- /dev/null
+++ b/apps/list.c
@@ -0,0 +1,578 @@
+/*
+ * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/provider.h>
+#include <openssl/safestack.h>
+#include "apps.h"
+#include "progs.h"
+#include "opt.h"
+
+static void list_cipher_fn(const EVP_CIPHER *c,
+                           const char *from, const char *to, void *arg)
+{
+    if (c != NULL) {
+        BIO_printf(arg, "  %s\n", EVP_CIPHER_name(c));
+    } else {
+        if (from == NULL)
+            from = "<undefined>";
+        if (to == NULL)
+            to = "<undefined>";
+        BIO_printf(arg, "  %s => %s\n", from, to);
+    }
+}
+
+DEFINE_STACK_OF(EVP_CIPHER)
+static int cipher_cmp(const EVP_CIPHER * const *a,
+                      const EVP_CIPHER * const *b)
+{
+    int ret = strcmp(EVP_CIPHER_name(*a), EVP_CIPHER_name(*b));
+
+    if (ret == 0)
+        ret = strcmp(OSSL_PROVIDER_name(EVP_CIPHER_provider(*a)),
+                     OSSL_PROVIDER_name(EVP_CIPHER_provider(*b)));
+
+    return ret;
+}
+
+static void collect_ciphers(EVP_CIPHER *cipher, void *stack)
+{
+    STACK_OF(EVP_CIPHER) *cipher_stack = stack;
+    sk_EVP_CIPHER_push(cipher_stack, cipher);
+    EVP_CIPHER_up_ref(cipher);
+}
+
+static void list_ciphers(void)
+{
+    STACK_OF(EVP_CIPHER) *ciphers = sk_EVP_CIPHER_new(cipher_cmp);
+    int i;
+
+    BIO_printf(bio_out, "Legacy:\n");
+    EVP_CIPHER_do_all_sorted(list_cipher_fn, bio_out);
+
+    BIO_printf(bio_out, "Provided:\n");
+    EVP_CIPHER_do_all_ex(NULL, collect_ciphers, ciphers);
+    sk_EVP_CIPHER_sort(ciphers);
+    for (i = 0; i < sk_EVP_CIPHER_num(ciphers); i++) {
+        const EVP_CIPHER *c = sk_EVP_CIPHER_value(ciphers, i);
+        BIO_printf(bio_out, "  %s", EVP_CIPHER_name(c));
+        BIO_printf(bio_out, " @ %s\n",
+                   OSSL_PROVIDER_name(EVP_CIPHER_provider(c)));
+    }
+    sk_EVP_CIPHER_pop_free(ciphers, EVP_CIPHER_meth_free);
+}
+
+static void list_md_fn(const EVP_MD *m,
+                       const char *from, const char *to, void *arg)
+{
+    if (m != NULL) {
+        BIO_printf(arg, "  %s\n", EVP_MD_name(m));
+    } else {
+        if (from == NULL)
+            from = "<undefined>";
+        if (to == NULL)
+            to = "<undefined>";
+        BIO_printf((BIO *)arg, "  %s => %s\n", from, to);
+    }
+}
+
+DEFINE_STACK_OF(EVP_MD)
+static int md_cmp(const EVP_MD * const *a, const EVP_MD * const *b)
+{
+    int ret = strcmp(EVP_MD_name(*a), EVP_MD_name(*b));
+
+    if (ret == 0)
+        ret = strcmp(OSSL_PROVIDER_name(EVP_MD_provider(*a)),
+                     OSSL_PROVIDER_name(EVP_MD_provider(*b)));
+
+    return ret;
+}
+
+static void collect_digests(EVP_MD *md, void *stack)
+{
+    STACK_OF(EVP_MD) *digest_stack = stack;
+    sk_EVP_MD_push(digest_stack, md);
+    EVP_MD_up_ref(md);
+}
+
+static void list_digests(void)
+{
+    STACK_OF(EVP_MD) *digests = sk_EVP_MD_new(md_cmp);
+    int i;
+
+    BIO_printf(bio_out, "Legacy:\n");
+    EVP_MD_do_all_sorted(list_md_fn, bio_out);
+
+    BIO_printf(bio_out, "Provided:\n");
+    EVP_MD_do_all_ex(NULL, collect_digests, digests);
+    sk_EVP_MD_sort(digests);
+    for (i = 0; i < sk_EVP_MD_num(digests); i++) {
+        const EVP_MD *c = sk_EVP_MD_value(digests, i);
+        BIO_printf(bio_out, "  %s", EVP_MD_name(c));
+        BIO_printf(bio_out, " @ %s\n",
+                   OSSL_PROVIDER_name(EVP_MD_provider(c)));
+    }
+    sk_EVP_MD_pop_free(digests, EVP_MD_meth_free);
+}
+
+static void list_mac_fn(const EVP_MAC *m,
+                        const char *from, const char *to, void *arg)
+{
+    if (m != NULL) {
+        BIO_printf(arg, "%s\n", EVP_MAC_name(m));
+    } else {
+        if (from == NULL)
+            from = "<undefined>";
+        if (to == NULL)
+            to = "<undefined>";
+        BIO_printf(arg, "%s => %s\n", from, to);
+    }
+}
+
+static void list_missing_help(void)
+{
+    const FUNCTION *fp;
+    const OPTIONS *o;
+
+    for (fp = functions; fp->name != NULL; fp++) {
+        if ((o = fp->help) != NULL) {
+            /* If there is help, list what flags are not documented. */
+            for ( ; o->name != NULL; o++) {
+                if (o->helpstr == NULL)
+                    BIO_printf(bio_out, "%s %s\n", fp->name, o->name);
+            }
+        } else if (fp->func != dgst_main) {
+            /* If not aliased to the dgst command, */
+            BIO_printf(bio_out, "%s *\n", fp->name);
+        }
+    }
+}
+
+static void list_objects(void)
+{
+    int max_nid = OBJ_new_nid(0);
+    int i;
+    char *oid_buf = NULL;
+    int oid_size = 0;
+
+    /* Skip 0, since that's NID_undef */
+    for (i = 1; i < max_nid; i++) {
+        const ASN1_OBJECT *obj = OBJ_nid2obj(i);
+        const char *sn = OBJ_nid2sn(i);
+        const char *ln = OBJ_nid2ln(i);
+        int n = 0;
+
+        /*
+         * If one of the retrieved objects somehow generated an error,
+         * we ignore it.  The check for NID_undef below will detect the
+         * error and simply skip to the next NID.
+         */
+        ERR_clear_error();
+
+        if (OBJ_obj2nid(obj) == NID_undef)
+            continue;
+
+        if ((n = OBJ_obj2txt(NULL, 0, obj, 1)) == 0) {
+            BIO_printf(bio_out, "# None-OID object: %s, %s\n", sn, ln);
+            continue;
+        }
+        if (n < 0)
+            break;               /* Error */
+
+        if (n > oid_size) {
+            oid_buf = OPENSSL_realloc(oid_buf, n + 1);
+            if (oid_buf == NULL) {
+                BIO_printf(bio_err, "ERROR: Memory allocation\n");
+                break;           /* Error */
+            }
+            oid_size = n + 1;
+        }
+        if (OBJ_obj2txt(oid_buf, oid_size, obj, 1) < 0)
+            break;               /* Error */
+        if (ln == NULL || strcmp(sn, ln) == 0)
+            BIO_printf(bio_out, "%s = %s\n", sn, oid_buf);
+        else
+            BIO_printf(bio_out, "%s = %s, %s\n", sn, ln, oid_buf);
+    }
+
+    OPENSSL_free(oid_buf);
+}
+
+static void list_options_for_command(const char *command)
+{
+    const FUNCTION *fp;
+    const OPTIONS *o;
+
+    for (fp = functions; fp->name != NULL; fp++)
+        if (strcmp(fp->name, command) == 0)
+            break;
+    if (fp->name == NULL) {
+        BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n",
+                command);
+        return;
+    }
+
+    if ((o = fp->help) == NULL)
+        return;
+
+    for ( ; o->name != NULL; o++) {
+        if (o->name == OPT_HELP_STR
+                || o->name == OPT_MORE_STR
+                || o->name[0] == '\0')
+            continue;
+        BIO_printf(bio_out, "%s %c\n", o->name, o->valtype);
+    }
+}
+
+static void list_type(FUNC_TYPE ft, int one)
+{
+    FUNCTION *fp;
+    int i = 0;
+    DISPLAY_COLUMNS dc;
+
+    memset(&dc, 0, sizeof(dc));
+    if (!one)
+        calculate_columns(functions, &dc);
+
+    for (fp = functions; fp->name != NULL; fp++) {
+        if (fp->type != ft)
+            continue;
+        if (one) {
+            BIO_printf(bio_out, "%s\n", fp->name);
+        } else {
+            if (i % dc.columns == 0 && i > 0)
+                BIO_printf(bio_out, "\n");
+            BIO_printf(bio_out, "%-*s", dc.width, fp->name);
+            i++;
+        }
+    }
+    if (!one)
+        BIO_printf(bio_out, "\n\n");
+}
+
+static void list_pkey(void)
+{
+    int i;
+
+    for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) {
+        const EVP_PKEY_ASN1_METHOD *ameth;
+        int pkey_id, pkey_base_id, pkey_flags;
+        const char *pinfo, *pem_str;
+        ameth = EVP_PKEY_asn1_get0(i);
+        EVP_PKEY_asn1_get0_info(&pkey_id, &pkey_base_id, &pkey_flags,
+                                &pinfo, &pem_str, ameth);
+        if (pkey_flags & ASN1_PKEY_ALIAS) {
+            BIO_printf(bio_out, "Name: %s\n", OBJ_nid2ln(pkey_id));
+            BIO_printf(bio_out, "\tAlias for: %s\n",
+                       OBJ_nid2ln(pkey_base_id));
+        } else {
+            BIO_printf(bio_out, "Name: %s\n", pinfo);
+            BIO_printf(bio_out, "\tType: %s Algorithm\n",
+                       pkey_flags & ASN1_PKEY_DYNAMIC ?
+                       "External" : "Builtin");
+            BIO_printf(bio_out, "\tOID: %s\n", OBJ_nid2ln(pkey_id));
+            if (pem_str == NULL)
+                pem_str = "(none)";
+            BIO_printf(bio_out, "\tPEM string: %s\n", pem_str);
+        }
+
+    }
+}
+
+static void list_pkey_meth(void)
+{
+    size_t i;
+    size_t meth_count = EVP_PKEY_meth_get_count();
+
+    for (i = 0; i < meth_count; i++) {
+        const EVP_PKEY_METHOD *pmeth = EVP_PKEY_meth_get0(i);
+        int pkey_id, pkey_flags;
+
+        EVP_PKEY_meth_get0_info(&pkey_id, &pkey_flags, pmeth);
+        BIO_printf(bio_out, "%s\n", OBJ_nid2ln(pkey_id));
+        BIO_printf(bio_out, "\tType: %s Algorithm\n",
+                   pkey_flags & ASN1_PKEY_DYNAMIC ?  "External" : "Builtin");
+    }
+}
+
+static void list_engines(void)
+{
+#ifndef OPENSSL_NO_ENGINE
+    ENGINE *e;
+
+    BIO_puts(bio_out, "Engines:\n");
+    e = ENGINE_get_first();
+    while (e) {
+        BIO_printf(bio_out, "%s\n", ENGINE_get_id(e));
+        e = ENGINE_get_next(e);
+    }
+#else
+    BIO_puts(bio_out, "Engine support is disabled.\n");
+#endif
+}
+
+static void list_disabled(void)
+{
+    BIO_puts(bio_out, "Disabled algorithms:\n");
+#ifdef OPENSSL_NO_ARIA
+    BIO_puts(bio_out, "ARIA\n");
+#endif
+#ifdef OPENSSL_NO_BF
+    BIO_puts(bio_out, "BF\n");
+#endif
+#ifdef OPENSSL_NO_BLAKE2
+    BIO_puts(bio_out, "BLAKE2\n");
+#endif
+#ifdef OPENSSL_NO_CAMELLIA
+    BIO_puts(bio_out, "CAMELLIA\n");
+#endif
+#ifdef OPENSSL_NO_CAST
+    BIO_puts(bio_out, "CAST\n");
+#endif
+#ifdef OPENSSL_NO_CMAC
+    BIO_puts(bio_out, "CMAC\n");
+#endif
+#ifdef OPENSSL_NO_CMS
+    BIO_puts(bio_out, "CMS\n");
+#endif
+#ifdef OPENSSL_NO_COMP
+    BIO_puts(bio_out, "COMP\n");
+#endif
+#ifdef OPENSSL_NO_DES
+    BIO_puts(bio_out, "DES\n");
+#endif
+#ifdef OPENSSL_NO_DGRAM
+    BIO_puts(bio_out, "DGRAM\n");
+#endif
+#ifdef OPENSSL_NO_DH
+    BIO_puts(bio_out, "DH\n");
+#endif
+#ifdef OPENSSL_NO_DSA
+    BIO_puts(bio_out, "DSA\n");
+#endif
+#if defined(OPENSSL_NO_DTLS)
+    BIO_puts(bio_out, "DTLS\n");
+#endif
+#if defined(OPENSSL_NO_DTLS1)
+    BIO_puts(bio_out, "DTLS1\n");
+#endif
+#if defined(OPENSSL_NO_DTLS1_2)
+    BIO_puts(bio_out, "DTLS1_2\n");
+#endif
+#ifdef OPENSSL_NO_EC
+    BIO_puts(bio_out, "EC\n");
+#endif
+#ifdef OPENSSL_NO_EC2M
+    BIO_puts(bio_out, "EC2M\n");
+#endif
+#ifdef OPENSSL_NO_ENGINE
+    BIO_puts(bio_out, "ENGINE\n");
+#endif
+#ifdef OPENSSL_NO_GOST
+    BIO_puts(bio_out, "GOST\n");
+#endif
+#ifdef OPENSSL_NO_IDEA
+    BIO_puts(bio_out, "IDEA\n");
+#endif
+#ifdef OPENSSL_NO_MD2
+    BIO_puts(bio_out, "MD2\n");
+#endif
+#ifdef OPENSSL_NO_MD4
+    BIO_puts(bio_out, "MD4\n");
+#endif
+#ifdef OPENSSL_NO_MD5
+    BIO_puts(bio_out, "MD5\n");
+#endif
+#ifdef OPENSSL_NO_MDC2
+    BIO_puts(bio_out, "MDC2\n");
+#endif
+#ifdef OPENSSL_NO_OCB
+    BIO_puts(bio_out, "OCB\n");
+#endif
+#ifdef OPENSSL_NO_OCSP
+    BIO_puts(bio_out, "OCSP\n");
+#endif
+#ifdef OPENSSL_NO_PSK
+    BIO_puts(bio_out, "PSK\n");
+#endif
+#ifdef OPENSSL_NO_RC2
+    BIO_puts(bio_out, "RC2\n");
+#endif
+#ifdef OPENSSL_NO_RC4
+    BIO_puts(bio_out, "RC4\n");
+#endif
+#ifdef OPENSSL_NO_RC5
+    BIO_puts(bio_out, "RC5\n");
+#endif
+#ifdef OPENSSL_NO_RMD160
+    BIO_puts(bio_out, "RMD160\n");
+#endif
+#ifdef OPENSSL_NO_RSA
+    BIO_puts(bio_out, "RSA\n");
+#endif
+#ifdef OPENSSL_NO_SCRYPT
+    BIO_puts(bio_out, "SCRYPT\n");
+#endif
+#ifdef OPENSSL_NO_SCTP
+    BIO_puts(bio_out, "SCTP\n");
+#endif
+#ifdef OPENSSL_NO_SEED
+    BIO_puts(bio_out, "SEED\n");
+#endif
+#ifdef OPENSSL_NO_SM2
+    BIO_puts(bio_out, "SM2\n");
+#endif
+#ifdef OPENSSL_NO_SM3
+    BIO_puts(bio_out, "SM3\n");
+#endif
+#ifdef OPENSSL_NO_SM4
+    BIO_puts(bio_out, "SM4\n");
+#endif
+#ifdef OPENSSL_NO_SOCK
+    BIO_puts(bio_out, "SOCK\n");
+#endif
+#ifdef OPENSSL_NO_SRP
+    BIO_puts(bio_out, "SRP\n");
+#endif
+#ifdef OPENSSL_NO_SRTP
+    BIO_puts(bio_out, "SRTP\n");
+#endif
+#ifdef OPENSSL_NO_SSL3
+    BIO_puts(bio_out, "SSL3\n");
+#endif
+#ifdef OPENSSL_NO_TLS1
+    BIO_puts(bio_out, "TLS1\n");
+#endif
+#ifdef OPENSSL_NO_TLS1_1
+    BIO_puts(bio_out, "TLS1_1\n");
+#endif
+#ifdef OPENSSL_NO_TLS1_2
+    BIO_puts(bio_out, "TLS1_2\n");
+#endif
+#ifdef OPENSSL_NO_WHIRLPOOL
+    BIO_puts(bio_out, "WHIRLPOOL\n");
+#endif
+#ifndef ZLIB
+    BIO_puts(bio_out, "ZLIB\n");
+#endif
+}
+
+/* Unified enum for help and list commands. */
+typedef enum HELPLIST_CHOICE {
+    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_ONE,
+    OPT_COMMANDS, OPT_DIGEST_COMMANDS, OPT_MAC_ALGORITHMS, OPT_OPTIONS,
+    OPT_DIGEST_ALGORITHMS, OPT_CIPHER_COMMANDS, OPT_CIPHER_ALGORITHMS,
+    OPT_PK_ALGORITHMS, OPT_PK_METHOD, OPT_ENGINES, OPT_DISABLED,
+    OPT_MISSING_HELP, OPT_OBJECTS
+} HELPLIST_CHOICE;
+
+const OPTIONS list_options[] = {
+    {"help", OPT_HELP, '-', "Display this summary"},
+    {"1", OPT_ONE, '-', "List in one column"},
+    {"commands", OPT_COMMANDS, '-', "List of standard commands"},
+    {"digest-commands", OPT_DIGEST_COMMANDS, '-',
+     "List of message digest commands"},
+    {"digest-algorithms", OPT_DIGEST_ALGORITHMS, '-',
+     "List of message digest algorithms"},
+    {"mac-algorithms", OPT_MAC_ALGORITHMS, '-',
+     "List of message authentication code algorithms"},
+    {"cipher-commands", OPT_CIPHER_COMMANDS, '-', "List of cipher commands"},
+    {"cipher-algorithms", OPT_CIPHER_ALGORITHMS, '-',
+     "List of cipher algorithms"},
+    {"public-key-algorithms", OPT_PK_ALGORITHMS, '-',
+     "List of public key algorithms"},
+    {"public-key-methods", OPT_PK_METHOD, '-',
+     "List of public key methods"},
+    {"engines", OPT_ENGINES, '-',
+     "List of loaded engines"},
+    {"disabled", OPT_DISABLED, '-',
+     "List of disabled features"},
+    {"missing-help", OPT_MISSING_HELP, '-',
+     "List missing detailed help strings"},
+    {"options", OPT_OPTIONS, 's',
+     "List options for specified command"},
+    {"objects", OPT_OBJECTS, '-',
+     "List built in objects (OID<->name mappings)"},
+    {NULL}
+};
+
+int list_main(int argc, char **argv)
+{
+    char *prog;
+    HELPLIST_CHOICE o;
+    int one = 0, done = 0;
+
+    prog = opt_init(argc, argv, list_options);
+    while ((o = opt_next()) != OPT_EOF) {
+        switch (o) {
+        case OPT_EOF:  /* Never hit, but suppresses warning */
+        case OPT_ERR:
+opthelp:
+            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
+            return 1;
+        case OPT_HELP:
+            opt_help(list_options);
+            break;
+        case OPT_ONE:
+            one = 1;
+            break;
+        case OPT_COMMANDS:
+            list_type(FT_general, one);
+            break;
+        case OPT_DIGEST_COMMANDS:
+            list_type(FT_md, one);
+            break;
+        case OPT_DIGEST_ALGORITHMS:
+            list_digests();
+            break;
+        case OPT_MAC_ALGORITHMS:
+            EVP_MAC_do_all_sorted(list_mac_fn, bio_out);
+            break;
+        case OPT_CIPHER_COMMANDS:
+            list_type(FT_cipher, one);
+            break;
+        case OPT_CIPHER_ALGORITHMS:
+            list_ciphers();
+            break;
+        case OPT_PK_ALGORITHMS:
+            list_pkey();
+            break;
+        case OPT_PK_METHOD:
+            list_pkey_meth();
+            break;
+        case OPT_ENGINES:
+            list_engines();
+            break;
+        case OPT_DISABLED:
+            list_disabled();
+            break;
+        case OPT_MISSING_HELP:
+            list_missing_help();
+            break;
+        case OPT_OBJECTS:
+            list_objects();
+            break;
+        case OPT_OPTIONS:
+            list_options_for_command(opt_arg());
+            break;
+        }
+        done = 1;
+    }
+    if (opt_num_rest() != 0) {
+        BIO_printf(bio_err, "Extra arguments given.\n");
+        goto opthelp;
+    }
+
+    if (!done)
+        goto opthelp;
+
+    return 0;
+}
diff --git a/apps/openssl.c b/apps/openssl.c
index d6820a1..b2fd630 100644
--- a/apps/openssl.c
+++ b/apps/openssl.c
@@ -29,17 +29,8 @@
 # include <unixio.h>
 #endif
 #include "apps.h"
-#define INCLUDE_FUNCTION_TABLE
 #include "progs.h"
 
-/* Structure to hold the number of columns to be displayed and the
- * field width used to display them.
- */
-typedef struct {
-    int columns;
-    int width;
-} DISPLAY_COLUMNS;
-
 /* Special sentinel to exit the program. */
 #define EXIT_THE_PROGRAM (-1)
 
@@ -51,31 +42,12 @@ typedef struct {
  */
 static LHASH_OF(FUNCTION) *prog_init(void);
 static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]);
-static void list_pkey(void);
-static void list_pkey_meth(void);
-static void list_type(FUNC_TYPE ft, int one);
-static void list_engines(void);
-static void list_disabled(void);
 char *default_config_file = NULL;
 
 BIO *bio_in = NULL;
 BIO *bio_out = NULL;
 BIO *bio_err = NULL;
 
-static void calculate_columns(DISPLAY_COLUMNS *dc)
-{
-    FUNCTION *f;
-    int len, maxlen = 0;
-
-    for (f = functions; f->name != NULL; ++f)
-        if (f->type == FT_general || f->type == FT_md || f->type == FT_cipher)
-            if ((len = strlen(f->name)) > maxlen)
-                maxlen = len;
-
-    dc->width = maxlen + 2;
-    dc->columns = (80 - 1) / dc->width;
-}
-
 static int apps_startup(void)
 {
 #ifdef SIGPIPE
@@ -408,256 +380,6 @@ int main(int argc, char *argv[])
     EXIT(ret);
 }
 
-static void list_cipher_fn(const EVP_CIPHER *c,
-                           const char *from, const char *to, void *arg)
-{
-    if (c != NULL) {
-        BIO_printf(arg, "%s\n", EVP_CIPHER_name(c));
-    } else {
-        if (from == NULL)
-            from = "<undefined>";
-        if (to == NULL)
-            to = "<undefined>";
-        BIO_printf(arg, "%s => %s\n", from, to);
-    }
-}
-
-static void list_md_fn(const EVP_MD *m,
-                       const char *from, const char *to, void *arg)
-{
-    if (m != NULL) {
-        BIO_printf(arg, "%s\n", EVP_MD_name(m));
-    } else {
-        if (from == NULL)
-            from = "<undefined>";
-        if (to == NULL)
-            to = "<undefined>";
-        BIO_printf((BIO *)arg, "%s => %s\n", from, to);
-    }
-}
-
-static void list_mac_fn(const EVP_MAC *m,
-                        const char *from, const char *to, void *arg)
-{
-    if (m != NULL) {
-        BIO_printf(arg, "%s\n", EVP_MAC_name(m));
-    } else {
-        if (from == NULL)
-            from = "<undefined>";
-        if (to == NULL)
-            to = "<undefined>";
-        BIO_printf(arg, "%s => %s\n", from, to);
-    }
-}
-
-static void list_missing_help(void)
-{
-    const FUNCTION *fp;
-    const OPTIONS *o;
-
-    for (fp = functions; fp->name != NULL; fp++) {
-        if ((o = fp->help) != NULL) {
-            /* If there is help, list what flags are not documented. */
-            for ( ; o->name != NULL; o++) {
-                if (o->helpstr == NULL)
-                    BIO_printf(bio_out, "%s %s\n", fp->name, o->name);
-            }
-        } else if (fp->func != dgst_main) {
-            /* If not aliased to the dgst command, */
-            BIO_printf(bio_out, "%s *\n", fp->name);
-        }
-    }
-}
-
-static void list_objects(void)
-{
-    int max_nid = OBJ_new_nid(0);
-    int i;
-    char *oid_buf = NULL;
-    int oid_size = 0;
-
-    /* Skip 0, since that's NID_undef */
-    for (i = 1; i < max_nid; i++) {
-        const ASN1_OBJECT *obj = OBJ_nid2obj(i);
-        const char *sn = OBJ_nid2sn(i);
-        const char *ln = OBJ_nid2ln(i);
-        int n = 0;
-
-        /*
-         * If one of the retrieved objects somehow generated an error,
-         * we ignore it.  The check for NID_undef below will detect the
-         * error and simply skip to the next NID.
-         */
-        ERR_clear_error();
-
-        if (OBJ_obj2nid(obj) == NID_undef)
-            continue;
-
-        if ((n = OBJ_obj2txt(NULL, 0, obj, 1)) == 0) {
-            BIO_printf(bio_out, "# None-OID object: %s, %s\n", sn, ln);
-            continue;
-        }
-        if (n < 0)
-            break;               /* Error */
-
-        if (n > oid_size) {
-            oid_buf = OPENSSL_realloc(oid_buf, n + 1);
-            if (oid_buf == NULL) {
-                BIO_printf(bio_err, "ERROR: Memory allocation\n");
-                break;           /* Error */
-            }
-            oid_size = n + 1;
-        }
-        if (OBJ_obj2txt(oid_buf, oid_size, obj, 1) < 0)
-            break;               /* Error */
-        if (ln == NULL || strcmp(sn, ln) == 0)
-            BIO_printf(bio_out, "%s = %s\n", sn, oid_buf);
-        else
-            BIO_printf(bio_out, "%s = %s, %s\n", sn, ln, oid_buf);
-    }
-
-    OPENSSL_free(oid_buf);
-}
-
-static void list_options_for_command(const char *command)
-{
-    const FUNCTION *fp;
-    const OPTIONS *o;
-
-    for (fp = functions; fp->name != NULL; fp++)
-        if (strcmp(fp->name, command) == 0)
-            break;
-    if (fp->name == NULL) {
-        BIO_printf(bio_err, "Invalid command '%s'; type \"help\" for a list.\n",
-                command);
-        return;
-    }
-
-    if ((o = fp->help) == NULL)
-        return;
-
-    for ( ; o->name != NULL; o++) {
-        if (o->name == OPT_HELP_STR
-                || o->name == OPT_MORE_STR
-                || o->name[0] == '\0')
-            continue;
-        BIO_printf(bio_out, "%s %c\n", o->name, o->valtype);
-    }
-}
-
-
-/* Unified enum for help and list commands. */
-typedef enum HELPLIST_CHOICE {
-    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_ONE,
-    OPT_COMMANDS, OPT_DIGEST_COMMANDS, OPT_MAC_ALGORITHMS, OPT_OPTIONS,
-    OPT_DIGEST_ALGORITHMS, OPT_CIPHER_COMMANDS, OPT_CIPHER_ALGORITHMS,
-    OPT_PK_ALGORITHMS, OPT_PK_METHOD, OPT_ENGINES, OPT_DISABLED,
-    OPT_MISSING_HELP, OPT_OBJECTS
-} HELPLIST_CHOICE;
-
-const OPTIONS list_options[] = {
-    {"help", OPT_HELP, '-', "Display this summary"},
-    {"1", OPT_ONE, '-', "List in one column"},
-    {"commands", OPT_COMMANDS, '-', "List of standard commands"},
-    {"digest-commands", OPT_DIGEST_COMMANDS, '-',
-     "List of message digest commands"},
-    {"digest-algorithms", OPT_DIGEST_ALGORITHMS, '-',
-     "List of message digest algorithms"},
-    {"mac-algorithms", OPT_MAC_ALGORITHMS, '-',
-     "List of message authentication code algorithms"},
-    {"cipher-commands", OPT_CIPHER_COMMANDS, '-', "List of cipher commands"},
-    {"cipher-algorithms", OPT_CIPHER_ALGORITHMS, '-',
-     "List of cipher algorithms"},
-    {"public-key-algorithms", OPT_PK_ALGORITHMS, '-',
-     "List of public key algorithms"},
-    {"public-key-methods", OPT_PK_METHOD, '-',
-     "List of public key methods"},
-    {"engines", OPT_ENGINES, '-',
-     "List of loaded engines"},
-    {"disabled", OPT_DISABLED, '-',
-     "List of disabled features"},
-    {"missing-help", OPT_MISSING_HELP, '-',
-     "List missing detailed help strings"},
-    {"options", OPT_OPTIONS, 's',
-     "List options for specified command"},
-    {"objects", OPT_OBJECTS, '-',
-     "List built in objects (OID<->name mappings)"},
-    {NULL}
-};
-
-int list_main(int argc, char **argv)
-{
-    char *prog;
-    HELPLIST_CHOICE o;
-    int one = 0, done = 0;
-
-    prog = opt_init(argc, argv, list_options);
-    while ((o = opt_next()) != OPT_EOF) {
-        switch (o) {
-        case OPT_EOF:  /* Never hit, but suppresses warning */
-        case OPT_ERR:
-opthelp:
-            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
-            return 1;
-        case OPT_HELP:
-            opt_help(list_options);
-            break;
-        case OPT_ONE:
-            one = 1;
-            break;
-        case OPT_COMMANDS:
-            list_type(FT_general, one);
-            break;
-        case OPT_DIGEST_COMMANDS:
-            list_type(FT_md, one);
-            break;
-        case OPT_DIGEST_ALGORITHMS:
-            EVP_MD_do_all_sorted(list_md_fn, bio_out);
-            break;
-        case OPT_MAC_ALGORITHMS:
-            EVP_MAC_do_all_sorted(list_mac_fn, bio_out);
-            break;
-        case OPT_CIPHER_COMMANDS:
-            list_type(FT_cipher, one);
-            break;
-        case OPT_CIPHER_ALGORITHMS:
-            EVP_CIPHER_do_all_sorted(list_cipher_fn, bio_out);
-            break;
-        case OPT_PK_ALGORITHMS:
-            list_pkey();
-            break;
-        case OPT_PK_METHOD:
-            list_pkey_meth();
-            break;
-        case OPT_ENGINES:
-            list_engines();
-            break;
-        case OPT_DISABLED:
-            list_disabled();
-            break;
-        case OPT_MISSING_HELP:
-            list_missing_help();
-            break;
-        case OPT_OBJECTS:
-            list_objects();
-            break;
-        case OPT_OPTIONS:
-            list_options_for_command(opt_arg());
-            break;
-        }
-        done = 1;
-    }
-    if (opt_num_rest() != 0) {
-        BIO_printf(bio_err, "Extra arguments given.\n");
-        goto opthelp;
-    }
-
-    if (!done)
-        goto opthelp;
-
-    return 0;
-}
-
 typedef enum HELP_CHOICE {
     OPT_hERR = -1, OPT_hEOF = 0, OPT_hHELP
 } HELP_CHOICE;
@@ -705,7 +427,7 @@ int help_main(int argc, char **argv)
         return 1;
     }
 
-    calculate_columns(&dc);
+    calculate_columns(functions, &dc);
     BIO_printf(bio_err, "Standard commands");
     i = 0;
     tp = FT_none;
@@ -735,32 +457,6 @@ int help_main(int argc, char **argv)
     return 0;
 }
 
-static void list_type(FUNC_TYPE ft, int one)
-{
-    FUNCTION *fp;
-    int i = 0;
-    DISPLAY_COLUMNS dc;
-
-    memset(&dc, 0, sizeof(dc));
-    if (!one)
-        calculate_columns(&dc);
-
-    for (fp = functions; fp->name != NULL; fp++) {
-        if (fp->type != ft)
-            continue;
-        if (one) {
-            BIO_printf(bio_out, "%s\n", fp->name);
-        } else {
-            if (i % dc.columns == 0 && i > 0)
-                BIO_printf(bio_out, "\n");
-            BIO_printf(bio_out, "%-*s", dc.width, fp->name);
-            i++;
-        }
-    }
-    if (!one)
-        BIO_printf(bio_out, "\n\n");
-}
-
 static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[])
 {
     FUNCTION f, *fp;
@@ -806,51 +502,6 @@ static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[])
     return 1;
 }
 
-static void list_pkey(void)
-{
-    int i;
-
-    for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) {
-        const EVP_PKEY_ASN1_METHOD *ameth;
-        int pkey_id, pkey_base_id, pkey_flags;
-        const char *pinfo, *pem_str;
-        ameth = EVP_PKEY_asn1_get0(i);
-        EVP_PKEY_asn1_get0_info(&pkey_id, &pkey_base_id, &pkey_flags,
-                                &pinfo, &pem_str, ameth);
-        if (pkey_flags & ASN1_PKEY_ALIAS) {
-            BIO_printf(bio_out, "Name: %s\n", OBJ_nid2ln(pkey_id));
-            BIO_printf(bio_out, "\tAlias for: %s\n",
-                       OBJ_nid2ln(pkey_base_id));
-        } else {
-            BIO_printf(bio_out, "Name: %s\n", pinfo);
-            BIO_printf(bio_out, "\tType: %s Algorithm\n",
-                       pkey_flags & ASN1_PKEY_DYNAMIC ?
-                       "External" : "Builtin");
-            BIO_printf(bio_out, "\tOID: %s\n", OBJ_nid2ln(pkey_id));
-            if (pem_str == NULL)
-                pem_str = "(none)";
-            BIO_printf(bio_out, "\tPEM string: %s\n", pem_str);
-        }
-
-    }
-}
-
-static void list_pkey_meth(void)
-{
-    size_t i;
-    size_t meth_count = EVP_PKEY_meth_get_count();
-
-    for (i = 0; i < meth_count; i++) {
-        const EVP_PKEY_METHOD *pmeth = EVP_PKEY_meth_get0(i);
-        int pkey_id, pkey_flags;
-
-        EVP_PKEY_meth_get0_info(&pkey_id, &pkey_flags, pmeth);
-        BIO_printf(bio_out, "%s\n", OBJ_nid2ln(pkey_id));
-        BIO_printf(bio_out, "\tType: %s Algorithm\n",
-                   pkey_flags & ASN1_PKEY_DYNAMIC ?  "External" : "Builtin");
-    }
-}
-
 static int function_cmp(const FUNCTION * a, const FUNCTION * b)
 {
     return strncmp(a->name, b->name, 8);
@@ -871,168 +522,6 @@ static int SortFnByName(const void *_f1, const void *_f2)
     return strcmp(f1->name, f2->name);
 }
 
-static void list_engines(void)
-{
-#ifndef OPENSSL_NO_ENGINE
-    ENGINE *e;
-
-    BIO_puts(bio_out, "Engines:\n");
-    e = ENGINE_get_first();
-    while (e) {
-        BIO_printf(bio_out, "%s\n", ENGINE_get_id(e));
-        e = ENGINE_get_next(e);
-    }
-#else
-    BIO_puts(bio_out, "Engine support is disabled.\n");
-#endif
-}
-
-static void list_disabled(void)
-{
-    BIO_puts(bio_out, "Disabled algorithms:\n");
-#ifdef OPENSSL_NO_ARIA
-    BIO_puts(bio_out, "ARIA\n");
-#endif
-#ifdef OPENSSL_NO_BF
-    BIO_puts(bio_out, "BF\n");
-#endif
-#ifdef OPENSSL_NO_BLAKE2
-    BIO_puts(bio_out, "BLAKE2\n");
-#endif
-#ifdef OPENSSL_NO_CAMELLIA
-    BIO_puts(bio_out, "CAMELLIA\n");
-#endif
-#ifdef OPENSSL_NO_CAST
-    BIO_puts(bio_out, "CAST\n");
-#endif
-#ifdef OPENSSL_NO_CMAC
-    BIO_puts(bio_out, "CMAC\n");
-#endif
-#ifdef OPENSSL_NO_CMS
-    BIO_puts(bio_out, "CMS\n");
-#endif
-#ifdef OPENSSL_NO_COMP
-    BIO_puts(bio_out, "COMP\n");
-#endif
-#ifdef OPENSSL_NO_DES
-    BIO_puts(bio_out, "DES\n");
-#endif
-#ifdef OPENSSL_NO_DGRAM
-    BIO_puts(bio_out, "DGRAM\n");
-#endif
-#ifdef OPENSSL_NO_DH
-    BIO_puts(bio_out, "DH\n");
-#endif
-#ifdef OPENSSL_NO_DSA
-    BIO_puts(bio_out, "DSA\n");
-#endif
-#if defined(OPENSSL_NO_DTLS)
-    BIO_puts(bio_out, "DTLS\n");
-#endif
-#if defined(OPENSSL_NO_DTLS1)
-    BIO_puts(bio_out, "DTLS1\n");
-#endif
-#if defined(OPENSSL_NO_DTLS1_2)
-    BIO_puts(bio_out, "DTLS1_2\n");
-#endif
-#ifdef OPENSSL_NO_EC
-    BIO_puts(bio_out, "EC\n");
-#endif
-#ifdef OPENSSL_NO_EC2M
-    BIO_puts(bio_out, "EC2M\n");
-#endif
-#ifdef OPENSSL_NO_ENGINE
-    BIO_puts(bio_out, "ENGINE\n");
-#endif
-#ifdef OPENSSL_NO_GOST
-    BIO_puts(bio_out, "GOST\n");
-#endif
-#ifdef OPENSSL_NO_IDEA
-    BIO_puts(bio_out, "IDEA\n");
-#endif
-#ifdef OPENSSL_NO_MD2
-    BIO_puts(bio_out, "MD2\n");
-#endif
-#ifdef OPENSSL_NO_MD4
-    BIO_puts(bio_out, "MD4\n");
-#endif
-#ifdef OPENSSL_NO_MD5
-    BIO_puts(bio_out, "MD5\n");
-#endif
-#ifdef OPENSSL_NO_MDC2
-    BIO_puts(bio_out, "MDC2\n");
-#endif
-#ifdef OPENSSL_NO_OCB
-    BIO_puts(bio_out, "OCB\n");
-#endif
-#ifdef OPENSSL_NO_OCSP
-    BIO_puts(bio_out, "OCSP\n");
-#endif
-#ifdef OPENSSL_NO_PSK
-    BIO_puts(bio_out, "PSK\n");
-#endif
-#ifdef OPENSSL_NO_RC2
-    BIO_puts(bio_out, "RC2\n");
-#endif
-#ifdef OPENSSL_NO_RC4
-    BIO_puts(bio_out, "RC4\n");
-#endif
-#ifdef OPENSSL_NO_RC5
-    BIO_puts(bio_out, "RC5\n");
-#endif
-#ifdef OPENSSL_NO_RMD160
-    BIO_puts(bio_out, "RMD160\n");
-#endif
-#ifdef OPENSSL_NO_RSA
-    BIO_puts(bio_out, "RSA\n");
-#endif
-#ifdef OPENSSL_NO_SCRYPT
-    BIO_puts(bio_out, "SCRYPT\n");
-#endif
-#ifdef OPENSSL_NO_SCTP
-    BIO_puts(bio_out, "SCTP\n");
-#endif
-#ifdef OPENSSL_NO_SEED
-    BIO_puts(bio_out, "SEED\n");
-#endif
-#ifdef OPENSSL_NO_SM2
-    BIO_puts(bio_out, "SM2\n");
-#endif
-#ifdef OPENSSL_NO_SM3
-    BIO_puts(bio_out, "SM3\n");
-#endif
-#ifdef OPENSSL_NO_SM4
-    BIO_puts(bio_out, "SM4\n");
-#endif
-#ifdef OPENSSL_NO_SOCK
-    BIO_puts(bio_out, "SOCK\n");
-#endif
-#ifdef OPENSSL_NO_SRP
-    BIO_puts(bio_out, "SRP\n");
-#endif
-#ifdef OPENSSL_NO_SRTP
-    BIO_puts(bio_out, "SRTP\n");
-#endif
-#ifdef OPENSSL_NO_SSL3
-    BIO_puts(bio_out, "SSL3\n");
-#endif
-#ifdef OPENSSL_NO_TLS1
-    BIO_puts(bio_out, "TLS1\n");
-#endif
-#ifdef OPENSSL_NO_TLS1_1
-    BIO_puts(bio_out, "TLS1_1\n");
-#endif
-#ifdef OPENSSL_NO_TLS1_2
-    BIO_puts(bio_out, "TLS1_2\n");
-#endif
-#ifdef OPENSSL_NO_WHIRLPOOL
-    BIO_puts(bio_out, "WHIRLPOOL\n");
-#endif
-#ifndef ZLIB
-    BIO_puts(bio_out, "ZLIB\n");
-#endif
-}
-
 static LHASH_OF(FUNCTION) *prog_init(void)
 {
     static LHASH_OF(FUNCTION) *ret = NULL;
diff --git a/apps/progs.c b/apps/progs.c
new file mode 100644
index 0000000..e7a06b9
--- /dev/null
+++ b/apps/progs.c
@@ -0,0 +1,398 @@
+/*
+ * WARNING: do not edit!
+ * Generated by apps/progs.pl
+ *
+ * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "progs.h"
+
+FUNCTION functions[] = {
+    {FT_general, "asn1parse", asn1parse_main, asn1parse_options},
+    {FT_general, "ca", ca_main, ca_options},
+#ifndef OPENSSL_NO_SOCK
+    {FT_general, "ciphers", ciphers_main, ciphers_options},
+#endif
+#ifndef OPENSSL_NO_CMS
+    {FT_general, "cms", cms_main, cms_options},
+#endif
+    {FT_general, "crl", crl_main, crl_options},
+    {FT_general, "crl2pkcs7", crl2pkcs7_main, crl2pkcs7_options},
+    {FT_general, "dgst", dgst_main, dgst_options},
+#ifndef OPENSSL_NO_DH
+    {FT_general, "dhparam", dhparam_main, dhparam_options},
+#endif
+#ifndef OPENSSL_NO_DSA
+    {FT_general, "dsa", dsa_main, dsa_options},
+#endif
+#ifndef OPENSSL_NO_DSA
+    {FT_general, "dsaparam", dsaparam_main, dsaparam_options},
+#endif
+#ifndef OPENSSL_NO_EC
+    {FT_general, "ec", ec_main, ec_options},
+#endif
+#ifndef OPENSSL_NO_EC
+    {FT_general, "ecparam", ecparam_main, ecparam_options},
+#endif
+    {FT_general, "enc", enc_main, enc_options},
+#ifndef OPENSSL_NO_ENGINE
+    {FT_general, "engine", engine_main, engine_options},
+#endif
+    {FT_general, "errstr", errstr_main, errstr_options},
+#ifndef OPENSSL_NO_DSA
+    {FT_general, "gendsa", gendsa_main, gendsa_options},
+#endif
+    {FT_general, "genpkey", genpkey_main, genpkey_options},
+#ifndef OPENSSL_NO_RSA
+    {FT_general, "genrsa", genrsa_main, genrsa_options},
+#endif
+    {FT_general, "help", help_main, help_options},
+    {FT_general, "info", info_main, info_options},
+    {FT_general, "kdf", kdf_main, kdf_options},
+    {FT_general, "list", list_main, list_options},
+    {FT_general, "mac", mac_main, mac_options},
+    {FT_general, "nseq", nseq_main, nseq_options},
+#ifndef OPENSSL_NO_OCSP
+    {FT_general, "ocsp", ocsp_main, ocsp_options},
+#endif
+    {FT_general, "passwd", passwd_main, passwd_options},
+#ifndef OPENSSL_NO_DES
+    {FT_general, "pkcs12", pkcs12_main, pkcs12_options},
+#endif
+    {FT_general, "pkcs7", pkcs7_main, pkcs7_options},
+    {FT_general, "pkcs8", pkcs8_main, pkcs8_options},
+    {FT_general, "pkey", pkey_main, pkey_options},
+    {FT_general, "pkeyparam", pkeyparam_main, pkeyparam_options},
+    {FT_general, "pkeyutl", pkeyutl_main, pkeyutl_options},
+    {FT_general, "prime", prime_main, prime_options},
+    {FT_general, "rand", rand_main, rand_options},
+    {FT_general, "rehash", rehash_main, rehash_options},
+    {FT_general, "req", req_main, req_options},
+    {FT_general, "rsa", rsa_main, rsa_options},
+#ifndef OPENSSL_NO_RSA
+    {FT_general, "rsautl", rsautl_main, rsautl_options},
+#endif
+#ifndef OPENSSL_NO_SOCK
+    {FT_general, "s_client", s_client_main, s_client_options},
+#endif
+#ifndef OPENSSL_NO_SOCK
+    {FT_general, "s_server", s_server_main, s_server_options},
+#endif
+#ifndef OPENSSL_NO_SOCK
+    {FT_general, "s_time", s_time_main, s_time_options},
+#endif
+    {FT_general, "sess_id", sess_id_main, sess_id_options},
+    {FT_general, "smime", smime_main, smime_options},
+    {FT_general, "speed", speed_main, speed_options},
+    {FT_general, "spkac", spkac_main, spkac_options},
+#ifndef OPENSSL_NO_SRP
+    {FT_general, "srp", srp_main, srp_options},
+#endif
+    {FT_general, "storeutl", storeutl_main, storeutl_options},
+#ifndef OPENSSL_NO_TS
+    {FT_general, "ts", ts_main, ts_options},
+#endif
+    {FT_general, "verify", verify_main, verify_options},
+    {FT_general, "version", version_main, version_options},
+    {FT_general, "x509", x509_main, x509_options},
+#ifndef OPENSSL_NO_MD2
+    {FT_md, "md2", dgst_main},
+#endif
+#ifndef OPENSSL_NO_MD4
+    {FT_md, "md4", dgst_main},
+#endif
+    {FT_md, "md5", dgst_main},
+#ifndef OPENSSL_NO_GOST
+    {FT_md, "gost", dgst_main},
+#endif
+    {FT_md, "sha1", dgst_main},
+    {FT_md, "sha224", dgst_main},
+    {FT_md, "sha256", dgst_main},
+    {FT_md, "sha384", dgst_main},
+    {FT_md, "sha512", dgst_main},
+    {FT_md, "sha512-224", dgst_main},
+    {FT_md, "sha512-256", dgst_main},
+    {FT_md, "sha3-224", dgst_main},
+    {FT_md, "sha3-256", dgst_main},
+    {FT_md, "sha3-384", dgst_main},
+    {FT_md, "sha3-512", dgst_main},
+    {FT_md, "shake128", dgst_main},
+    {FT_md, "shake256", dgst_main},
+#ifndef OPENSSL_NO_MDC2
+    {FT_md, "mdc2", dgst_main},
+#endif
+#ifndef OPENSSL_NO_RMD160
+    {FT_md, "rmd160", dgst_main},
+#endif
+#ifndef OPENSSL_NO_BLAKE2
+    {FT_md, "blake2b512", dgst_main},
+#endif
+#ifndef OPENSSL_NO_BLAKE2
+    {FT_md, "blake2s256", dgst_main},
+#endif
+#ifndef OPENSSL_NO_SM3
+    {FT_md, "sm3", dgst_main},
+#endif
+    {FT_cipher, "aes-128-cbc", enc_main, enc_options},
+    {FT_cipher, "aes-128-ecb", enc_main, enc_options},
+    {FT_cipher, "aes-192-cbc", enc_main, enc_options},
+    {FT_cipher, "aes-192-ecb", enc_main, enc_options},
+    {FT_cipher, "aes-256-cbc", enc_main, enc_options},
+    {FT_cipher, "aes-256-ecb", enc_main, enc_options},
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-128-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-128-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-128-ctr", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-128-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-128-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-128-cfb1", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-128-cfb8", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-192-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-192-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-192-ctr", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-192-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-192-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-192-cfb1", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-192-cfb8", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-256-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-256-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-256-ctr", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-256-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-256-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-256-cfb1", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_ARIA
+    {FT_cipher, "aria-256-cfb8", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+    {FT_cipher, "camellia-128-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+    {FT_cipher, "camellia-128-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+    {FT_cipher, "camellia-192-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+    {FT_cipher, "camellia-192-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+    {FT_cipher, "camellia-256-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+    {FT_cipher, "camellia-256-ecb", enc_main, enc_options},
+#endif
+    {FT_cipher, "base64", enc_main, enc_options},
+#ifdef ZLIB
+    {FT_cipher, "zlib", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des3", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "desx", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_IDEA
+    {FT_cipher, "idea", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_SEED
+    {FT_cipher, "seed", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC4
+    {FT_cipher, "rc4", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC4
+    {FT_cipher, "rc4-40", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC2
+    {FT_cipher, "rc2", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_BF
+    {FT_cipher, "bf", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_CAST
+    {FT_cipher, "cast", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC5
+    {FT_cipher, "rc5", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des-ede", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des-ede3", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des-ede-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des-ede3-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des-ede-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des-ede3-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des-ede-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_DES
+    {FT_cipher, "des-ede3-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_IDEA
+    {FT_cipher, "idea-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_IDEA
+    {FT_cipher, "idea-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_IDEA
+    {FT_cipher, "idea-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_IDEA
+    {FT_cipher, "idea-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_SEED
+    {FT_cipher, "seed-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_SEED
+    {FT_cipher, "seed-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_SEED
+    {FT_cipher, "seed-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_SEED
+    {FT_cipher, "seed-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC2
+    {FT_cipher, "rc2-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC2
+    {FT_cipher, "rc2-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC2
+    {FT_cipher, "rc2-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC2
+    {FT_cipher, "rc2-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC2
+    {FT_cipher, "rc2-64-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC2
+    {FT_cipher, "rc2-40-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_BF
+    {FT_cipher, "bf-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_BF
+    {FT_cipher, "bf-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_BF
+    {FT_cipher, "bf-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_BF
+    {FT_cipher, "bf-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_CAST
+    {FT_cipher, "cast5-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_CAST
+    {FT_cipher, "cast5-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_CAST
+    {FT_cipher, "cast5-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_CAST
+    {FT_cipher, "cast5-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_CAST
+    {FT_cipher, "cast-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC5
+    {FT_cipher, "rc5-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC5
+    {FT_cipher, "rc5-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC5
+    {FT_cipher, "rc5-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_RC5
+    {FT_cipher, "rc5-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_SM4
+    {FT_cipher, "sm4-cbc", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_SM4
+    {FT_cipher, "sm4-ecb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_SM4
+    {FT_cipher, "sm4-cfb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_SM4
+    {FT_cipher, "sm4-ofb", enc_main, enc_options},
+#endif
+#ifndef OPENSSL_NO_SM4
+    {FT_cipher, "sm4-ctr", enc_main, enc_options},
+#endif
+    {0, NULL, NULL}
+};
diff --git a/apps/progs.h b/apps/progs.h
new file mode 100644
index 0000000..664c714
--- /dev/null
+++ b/apps/progs.h
@@ -0,0 +1,119 @@
+/*
+ * WARNING: do not edit!
+ * Generated by apps/progs.pl
+ *
+ * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "function.h"
+
+extern int asn1parse_main(int argc, char *argv[]);
+extern int ca_main(int argc, char *argv[]);
+extern int ciphers_main(int argc, char *argv[]);
+extern int cms_main(int argc, char *argv[]);
+extern int crl_main(int argc, char *argv[]);
+extern int crl2pkcs7_main(int argc, char *argv[]);
+extern int dgst_main(int argc, char *argv[]);
+extern int dhparam_main(int argc, char *argv[]);
+extern int dsa_main(int argc, char *argv[]);
+extern int dsaparam_main(int argc, char *argv[]);
+extern int ec_main(int argc, char *argv[]);
+extern int ecparam_main(int argc, char *argv[]);
+extern int enc_main(int argc, char *argv[]);
+extern int engine_main(int argc, char *argv[]);
+extern int errstr_main(int argc, char *argv[]);
+extern int gendsa_main(int argc, char *argv[]);
+extern int genpkey_main(int argc, char *argv[]);
+extern int genrsa_main(int argc, char *argv[]);
+extern int help_main(int argc, char *argv[]);
+extern int info_main(int argc, char *argv[]);
+extern int kdf_main(int argc, char *argv[]);
+extern int list_main(int argc, char *argv[]);
+extern int mac_main(int argc, char *argv[]);
+extern int nseq_main(int argc, char *argv[]);
+extern int ocsp_main(int argc, char *argv[]);
+extern int passwd_main(int argc, char *argv[]);
+extern int pkcs12_main(int argc, char *argv[]);
+extern int pkcs7_main(int argc, char *argv[]);
+extern int pkcs8_main(int argc, char *argv[]);
+extern int pkey_main(int argc, char *argv[]);
+extern int pkeyparam_main(int argc, char *argv[]);
+extern int pkeyutl_main(int argc, char *argv[]);
+extern int prime_main(int argc, char *argv[]);
+extern int rand_main(int argc, char *argv[]);
+extern int rehash_main(int argc, char *argv[]);
+extern int req_main(int argc, char *argv[]);
+extern int rsa_main(int argc, char *argv[]);
+extern int rsautl_main(int argc, char *argv[]);
+extern int s_client_main(int argc, char *argv[]);
+extern int s_server_main(int argc, char *argv[]);
+extern int s_time_main(int argc, char *argv[]);
+extern int sess_id_main(int argc, char *argv[]);
+extern int smime_main(int argc, char *argv[]);
+extern int speed_main(int argc, char *argv[]);
+extern int spkac_main(int argc, char *argv[]);
+extern int srp_main(int argc, char *argv[]);
+extern int storeutl_main(int argc, char *argv[]);
+extern int ts_main(int argc, char *argv[]);
+extern int verify_main(int argc, char *argv[]);
+extern int version_main(int argc, char *argv[]);
+extern int x509_main(int argc, char *argv[]);
+
+extern const OPTIONS asn1parse_options[];
+extern const OPTIONS ca_options[];
+extern const OPTIONS ciphers_options[];
+extern const OPTIONS cms_options[];
+extern const OPTIONS crl_options[];
+extern const OPTIONS crl2pkcs7_options[];
+extern const OPTIONS dgst_options[];
+extern const OPTIONS dhparam_options[];
+extern const OPTIONS dsa_options[];
+extern const OPTIONS dsaparam_options[];
+extern const OPTIONS ec_options[];
+extern const OPTIONS ecparam_options[];
+extern const OPTIONS enc_options[];
+extern const OPTIONS engine_options[];
+extern const OPTIONS errstr_options[];
+extern const OPTIONS gendsa_options[];
+extern const OPTIONS genpkey_options[];
+extern const OPTIONS genrsa_options[];
+extern const OPTIONS help_options[];
+extern const OPTIONS info_options[];
+extern const OPTIONS kdf_options[];
+extern const OPTIONS list_options[];
+extern const OPTIONS mac_options[];
+extern const OPTIONS nseq_options[];
+extern const OPTIONS ocsp_options[];
+extern const OPTIONS passwd_options[];
+extern const OPTIONS pkcs12_options[];
+extern const OPTIONS pkcs7_options[];
+extern const OPTIONS pkcs8_options[];
+extern const OPTIONS pkey_options[];
+extern const OPTIONS pkeyparam_options[];
+extern const OPTIONS pkeyutl_options[];
+extern const OPTIONS prime_options[];
+extern const OPTIONS rand_options[];
+extern const OPTIONS rehash_options[];
+extern const OPTIONS req_options[];
+extern const OPTIONS rsa_options[];
+extern const OPTIONS rsautl_options[];
+extern const OPTIONS s_client_options[];
+extern const OPTIONS s_server_options[];
+extern const OPTIONS s_time_options[];
+extern const OPTIONS sess_id_options[];
+extern const OPTIONS smime_options[];
+extern const OPTIONS speed_options[];
+extern const OPTIONS spkac_options[];
+extern const OPTIONS srp_options[];
+extern const OPTIONS storeutl_options[];
+extern const OPTIONS ts_options[];
+extern const OPTIONS verify_options[];
+extern const OPTIONS version_options[];
+extern const OPTIONS x509_options[];
+
+extern FUNCTION functions[];
diff --git a/apps/progs.pl b/apps/progs.pl
index 3aec756..1b304a0 100644
--- a/apps/progs.pl
+++ b/apps/progs.pl
@@ -14,6 +14,10 @@ use warnings;
 use lib '.';
 use configdata qw/@disablables %unified_info/;
 
+my $opt          = shift @ARGV;
+die "Unrecognised option, must be -C or -H\n"
+    unless ($opt eq '-H' || $opt eq '-C');
+
 my %commands     = ();
 my $cmdre        = qr/^\s*int\s+([a-z_][a-z0-9_]*)_main\(\s*int\s+argc\s*,/;
 my $apps_openssl = shift @ARGV;
@@ -38,7 +42,8 @@ foreach my $filename (@openssl_source) {
 
 @ARGV = sort keys %commands;
 
-print <<"EOF";
+if ($opt eq '-H') {
+    print <<"EOF";
 /*
  * WARNING: do not edit!
  * Generated by apps/progs.pl
@@ -51,134 +56,139 @@ print <<"EOF";
  * https://www.openssl.org/source/license.html
  */
 
-#include <openssl/lhash.h>
-#include "opt.h"
+#include "function.h"
 
-typedef enum FUNC_TYPE {
-    FT_none, FT_general, FT_md, FT_cipher, FT_pkey,
-    FT_md_alg, FT_cipher_alg
-} FUNC_TYPE;
+EOF
 
-typedef struct function_st {
-    FUNC_TYPE type;
-    const char *name;
-    int (*func)(int argc, char *argv[]);
-    const OPTIONS *help;
-} FUNCTION;
+    foreach (@ARGV) {
+        printf "extern int %s_main(int argc, char *argv[]);\n", $_;
+    }
+    print "\n";
 
-DEFINE_LHASH_OF(FUNCTION);
+    foreach (@ARGV) {
+        printf "extern const OPTIONS %s_options[];\n", $_;
+    }
+    print "\n";
+    print "extern FUNCTION functions[];\n";
+}
 
-EOF
+if ($opt eq '-C') {
+    print <<"EOF";
+/*
+ * WARNING: do not edit!
+ * Generated by apps/progs.pl
+ *
+ * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
 
-foreach (@ARGV) {
-    printf "extern int %s_main(int argc, char *argv[]);\n", $_;
-}
-print "\n";
+#include "progs.h"
 
-foreach (@ARGV) {
-    printf "extern const OPTIONS %s_options[];\n", $_;
-}
-print "\n";
-
-my %cmd_disabler = (
-    ciphers  => "sock",
-    genrsa   => "rsa",
-    rsautl   => "rsa",
-    gendsa   => "dsa",
-    dsaparam => "dsa",
-    gendh    => "dh",
-    dhparam  => "dh",
-    ecparam  => "ec",
-    pkcs12   => "des",
-);
-
-print "#ifdef INCLUDE_FUNCTION_TABLE\n";
-print "static FUNCTION functions[] = {\n";
-foreach my $cmd ( @ARGV ) {
-    my $str = "    {FT_general, \"$cmd\", ${cmd}_main, ${cmd}_options},\n";
-    if ($cmd =~ /^s_/) {
-        print "#ifndef OPENSSL_NO_SOCK\n${str}#endif\n";
-    } elsif (grep { $cmd eq $_ } @disablables) {
-        print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n";
-    } elsif (my $disabler = $cmd_disabler{$cmd}) {
-        print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
-    } else {
-        print $str;
+EOF
+
+    my %cmd_disabler = (
+        ciphers  => "sock",
+        genrsa   => "rsa",
+        rsautl   => "rsa",
+        gendsa   => "dsa",
+        dsaparam => "dsa",
+        gendh    => "dh",
+        dhparam  => "dh",
+        ecparam  => "ec",
+        pkcs12   => "des",
+    );
+
+    print "FUNCTION functions[] = {\n";
+    foreach my $cmd ( @ARGV ) {
+        my $str =
+            "    {FT_general, \"$cmd\", ${cmd}_main, ${cmd}_options},\n";
+        if ($cmd =~ /^s_/) {
+            print "#ifndef OPENSSL_NO_SOCK\n${str}#endif\n";
+        } elsif (grep { $cmd eq $_ } @disablables) {
+            print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n";
+        } elsif (my $disabler = $cmd_disabler{$cmd}) {
+            print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
+        } else {
+            print $str;
+        }
     }
-}
 
-my %md_disabler = (
-    blake2b512 => "blake2",
-    blake2s256 => "blake2",
-);
-foreach my $cmd (
-    "md2", "md4", "md5",
-    "gost",
-    "sha1", "sha224", "sha256", "sha384",
-    "sha512", "sha512-224", "sha512-256",
-    "sha3-224", "sha3-256", "sha3-384", "sha3-512",
-    "shake128", "shake256",
-    "mdc2", "rmd160", "blake2b512", "blake2s256",
-    "sm3"
-) {
-    my $str = "    {FT_md, \"$cmd\", dgst_main},\n";
-    if (grep { $cmd eq $_ } @disablables) {
-        print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n";
-    } elsif (my $disabler = $md_disabler{$cmd}) {
-        print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
-    } else {
-        print $str;
+    my %md_disabler = (
+        blake2b512 => "blake2",
+        blake2s256 => "blake2",
+    );
+    foreach my $cmd (
+        "md2", "md4", "md5",
+        "gost",
+        "sha1", "sha224", "sha256", "sha384",
+        "sha512", "sha512-224", "sha512-256",
+        "sha3-224", "sha3-256", "sha3-384", "sha3-512",
+        "shake128", "shake256",
+        "mdc2", "rmd160", "blake2b512", "blake2s256",
+        "sm3"
+    ) {
+        my $str = "    {FT_md, \"$cmd\", dgst_main},\n";
+        if (grep { $cmd eq $_ } @disablables) {
+            print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n";
+        } elsif (my $disabler = $md_disabler{$cmd}) {
+            print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
+        } else {
+            print $str;
+        }
     }
-}
 
-my %cipher_disabler = (
-    des3  => "des",
-    desx  => "des",
-    cast5 => "cast",
-);
-foreach my $cmd (
-    "aes-128-cbc", "aes-128-ecb",
-    "aes-192-cbc", "aes-192-ecb",
-    "aes-256-cbc", "aes-256-ecb",
-    "aria-128-cbc", "aria-128-cfb",
-    "aria-128-ctr", "aria-128-ecb", "aria-128-ofb",
-    "aria-128-cfb1", "aria-128-cfb8",
-    "aria-192-cbc", "aria-192-cfb",
-    "aria-192-ctr", "aria-192-ecb", "aria-192-ofb",
-    "aria-192-cfb1", "aria-192-cfb8",
-    "aria-256-cbc", "aria-256-cfb",
-    "aria-256-ctr", "aria-256-ecb", "aria-256-ofb",
-    "aria-256-cfb1", "aria-256-cfb8",
-    "camellia-128-cbc", "camellia-128-ecb",
-    "camellia-192-cbc", "camellia-192-ecb",
-    "camellia-256-cbc", "camellia-256-ecb",
-    "base64", "zlib",
-    "des", "des3", "desx", "idea", "seed", "rc4", "rc4-40",
-    "rc2", "bf", "cast", "rc5",
-    "des-ecb", "des-ede", "des-ede3",
-    "des-cbc", "des-ede-cbc","des-ede3-cbc",
-    "des-cfb", "des-ede-cfb","des-ede3-cfb",
-    "des-ofb", "des-ede-ofb","des-ede3-ofb",
-    "idea-cbc","idea-ecb", "idea-cfb", "idea-ofb",
-    "seed-cbc","seed-ecb", "seed-cfb", "seed-ofb",
-    "rc2-cbc", "rc2-ecb", "rc2-cfb","rc2-ofb", "rc2-64-cbc", "rc2-40-cbc",
-    "bf-cbc", "bf-ecb", "bf-cfb", "bf-ofb",
-    "cast5-cbc","cast5-ecb", "cast5-cfb","cast5-ofb",
-    "cast-cbc", "rc5-cbc", "rc5-ecb", "rc5-cfb", "rc5-ofb",
-    "sm4-cbc", "sm4-ecb", "sm4-cfb", "sm4-ofb", "sm4-ctr"
-) {
-    my $str = "    {FT_cipher, \"$cmd\", enc_main, enc_options},\n";
-    (my $algo = $cmd) =~ s/-.*//g;
-    if ($cmd eq "zlib") {
-        print "#ifdef ZLIB\n${str}#endif\n";
-    } elsif (grep { $algo eq $_ } @disablables) {
-        print "#ifndef OPENSSL_NO_" . uc($algo) . "\n${str}#endif\n";
-    } elsif (my $disabler = $cipher_disabler{$algo}) {
-        print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
-    } else {
-        print $str;
+    my %cipher_disabler = (
+        des3  => "des",
+        desx  => "des",
+        cast5 => "cast",
+    );
+    foreach my $cmd (
+        "aes-128-cbc", "aes-128-ecb",
+        "aes-192-cbc", "aes-192-ecb",
+        "aes-256-cbc", "aes-256-ecb",
+        "aria-128-cbc", "aria-128-cfb",
+        "aria-128-ctr", "aria-128-ecb", "aria-128-ofb",
+        "aria-128-cfb1", "aria-128-cfb8",
+        "aria-192-cbc", "aria-192-cfb",
+        "aria-192-ctr", "aria-192-ecb", "aria-192-ofb",
+        "aria-192-cfb1", "aria-192-cfb8",
+        "aria-256-cbc", "aria-256-cfb",
+        "aria-256-ctr", "aria-256-ecb", "aria-256-ofb",
+        "aria-256-cfb1", "aria-256-cfb8",
+        "camellia-128-cbc", "camellia-128-ecb",
+        "camellia-192-cbc", "camellia-192-ecb",
+        "camellia-256-cbc", "camellia-256-ecb",
+        "base64", "zlib",
+        "des", "des3", "desx", "idea", "seed", "rc4", "rc4-40",
+        "rc2", "bf", "cast", "rc5",
+        "des-ecb", "des-ede", "des-ede3",
+        "des-cbc", "des-ede-cbc","des-ede3-cbc",
+        "des-cfb", "des-ede-cfb","des-ede3-cfb",
+        "des-ofb", "des-ede-ofb","des-ede3-ofb",
+        "idea-cbc","idea-ecb", "idea-cfb", "idea-ofb",
+        "seed-cbc","seed-ecb", "seed-cfb", "seed-ofb",
+        "rc2-cbc", "rc2-ecb", "rc2-cfb","rc2-ofb", "rc2-64-cbc", "rc2-40-cbc",
+        "bf-cbc", "bf-ecb", "bf-cfb", "bf-ofb",
+        "cast5-cbc","cast5-ecb", "cast5-cfb","cast5-ofb",
+        "cast-cbc", "rc5-cbc", "rc5-ecb", "rc5-cfb", "rc5-ofb",
+        "sm4-cbc", "sm4-ecb", "sm4-cfb", "sm4-ofb", "sm4-ctr"
+    ) {
+        my $str = "    {FT_cipher, \"$cmd\", enc_main, enc_options},\n";
+        (my $algo = $cmd) =~ s/-.*//g;
+        if ($cmd eq "zlib") {
+            print "#ifdef ZLIB\n${str}#endif\n";
+        } elsif (grep { $algo eq $_ } @disablables) {
+            print "#ifndef OPENSSL_NO_" . uc($algo) . "\n${str}#endif\n";
+        } elsif (my $disabler = $cipher_disabler{$algo}) {
+            print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
+        } else {
+            print $str;
+        }
     }
-}
 
-print "    {0, NULL, NULL}\n};\n";
-print "#endif\n";
+    print "    {0, NULL, NULL}\n};\n";
+}
diff --git a/crypto/build.info b/crypto/build.info
index fccca08..b9e35b9 100644
--- a/crypto/build.info
+++ b/crypto/build.info
@@ -59,7 +59,8 @@ IF[{- !$disabled{asm} && $config{processor} ne '386' -}]
 ENDIF
 
 # The Core
-$CORE_COMMON=provider_core.c provider_predefined.c core_fetch.c core_namemap.c
+$CORE_COMMON=provider_core.c provider_predefined.c \
+        core_fetch.c core_algorithm.c core_namemap.c
 
 SOURCE[../libcrypto]=$CORE_COMMON provider_conf.c
 SOURCE[../providers/fips]=$CORE_COMMON
diff --git a/crypto/core_algorithm.c b/crypto/core_algorithm.c
new file mode 100644
index 0000000..bbef1c3
--- /dev/null
+++ b/crypto/core_algorithm.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core.h>
+#include <openssl/core_numbers.h>
+#include "internal/core.h"
+#include "internal/property.h"
+#include "internal/provider.h"
+
+struct algorithm_data_st {
+    OPENSSL_CTX *libctx;
+    int operation_id;            /* May be zero for finding them all */
+    void (*fn)(OSSL_PROVIDER *, const OSSL_ALGORITHM *, int no_store,
+               void *data);
+    void *data;
+};
+
+static int algorithm_do_this(OSSL_PROVIDER *provider, void *cbdata)
+{
+    struct algorithm_data_st *data = cbdata;
+    int no_store = 0;    /* Assume caching is ok */
+    int first_operation = 1;
+    int last_operation = OSSL_OP__HIGHEST;
+    int cur_operation;
+    int ok = 0;
+
+    if (data->operation_id != 0)
+        first_operation = last_operation = data->operation_id;
+
+    for (cur_operation = first_operation;
+         cur_operation <= last_operation;
+         cur_operation++) {
+        const OSSL_ALGORITHM *map =
+            ossl_provider_query_operation(provider, data->operation_id,
+                                          &no_store);
+
+        if (map == NULL)
+            break;
+
+        ok = 1;                  /* As long as we've found *something* */
+        while (map->algorithm_name != NULL) {
+            const OSSL_ALGORITHM *thismap = map++;
+
+            data->fn(provider, thismap, no_store, data->data);
+        }
+    }
+
+    return ok;
+}
+
+void ossl_algorithm_do_all(OPENSSL_CTX *libctx, int operation_id,
+                           OSSL_PROVIDER *provider,
+                           void (*fn)(OSSL_PROVIDER *provider,
+                                      const OSSL_ALGORITHM *algo,
+                                      int no_store, void *data),
+                           void *data)
+{
+    struct algorithm_data_st cbdata;
+
+    cbdata.libctx = libctx;
+    cbdata.operation_id = operation_id;
+    cbdata.fn = fn;
+    cbdata.data = data;
+
+    if (provider == NULL) {
+        ossl_provider_forall_loaded(libctx, algorithm_do_this, &cbdata);
+    } else {
+        algorithm_do_this(provider, &cbdata);
+    }
+}
diff --git a/crypto/core_fetch.c b/crypto/core_fetch.c
index 56a3c5c..c1c8158 100644
--- a/crypto/core_fetch.c
+++ b/crypto/core_fetch.c
@@ -24,55 +24,45 @@ struct construct_data_st {
     void *mcm_data;
 };
 
-static int ossl_method_construct_this(OSSL_PROVIDER *provider, void *cbdata)
+static void ossl_method_construct_this(OSSL_PROVIDER *provider,
+                                       const OSSL_ALGORITHM *algo,
+                                       int no_store, void *cbdata)
 {
     struct construct_data_st *data = cbdata;
-    int no_store = 0;    /* Assume caching is ok */
-    const OSSL_ALGORITHM *map =
-        ossl_provider_query_operation(provider, data->operation_id, &no_store);
-
-    if (map == NULL)
-        return 0;
-
-    while (map->algorithm_name != NULL) {
-        const OSSL_ALGORITHM *thismap = map++;
-        void *method = NULL;
-
-        if ((method = data->mcm->construct(thismap->algorithm_name,
-                                           thismap->implementation, provider,
-                                           data->mcm_data)) == NULL)
-            continue;
+    void *method = NULL;
 
+    if ((method = data->mcm->construct(algo->algorithm_name,
+                                       algo->implementation, provider,
+                                       data->mcm_data)) == NULL)
+        return;
+
+    /*
+     * Note regarding putting the method in stores:
+     *
+     * we don't need to care if it actually got in or not here.
+     * If it didn't get in, it will simply not be available when
+     * ossl_method_construct() tries to get it from the store.
+     *
+     * It is *expected* that the put function increments the refcnt
+     * of the passed method.
+     */
+
+    if (data->force_store || !no_store) {
         /*
-         * Note regarding putting the method in stores:
-         *
-         * we don't need to care if it actually got in or not here.
-         * If it didn't get in, it will simply not be available when
-         * ossl_method_construct() tries to get it from the store.
-         *
-         * It is *expected* that the put function increments the refcnt
-         * of the passed method.
+         * If we haven't been told not to store,
+         * add to the global store
          */
-
-        if (data->force_store || !no_store) {
-            /*
-             * If we haven't been told not to store,
-             * add to the global store
-             */
-            data->mcm->put(data->libctx, NULL, method, data->operation_id,
-                           thismap->algorithm_name,
-                           thismap->property_definition, data->mcm_data);
-        }
-
-        data->mcm->put(data->libctx, data->store, method, data->operation_id,
-                       thismap->algorithm_name, thismap->property_definition,
-                       data->mcm_data);
-
-        /* refcnt-- because we're dropping the reference */
-        data->mcm->destruct(method, data->mcm_data);
+        data->mcm->put(data->libctx, NULL, method, data->operation_id,
+                       algo->algorithm_name,
+                       algo->property_definition, data->mcm_data);
     }
 
-    return 1;
+    data->mcm->put(data->libctx, data->store, method, data->operation_id,
+                   algo->algorithm_name, algo->property_definition,
+                   data->mcm_data);
+
+    /* refcnt-- because we're dropping the reference */
+    data->mcm->destruct(method, data->mcm_data);
 }
 
 void *ossl_method_construct(OPENSSL_CTX *libctx, int operation_id,
@@ -99,8 +89,8 @@ void *ossl_method_construct(OPENSSL_CTX *libctx, int operation_id,
         cbdata.force_store = force_store;
         cbdata.mcm = mcm;
         cbdata.mcm_data = mcm_data;
-        ossl_provider_forall_loaded(libctx, ossl_method_construct_this,
-                                    &cbdata);
+        ossl_algorithm_do_all(libctx, operation_id, NULL,
+                              ossl_method_construct_this, &cbdata);
 
         method = mcm->get(libctx, cbdata.store, operation_id, name,
                           propquery, mcm_data);
diff --git a/crypto/evp/cmeth_lib.c b/crypto/evp/cmeth_lib.c
index 40aca34..51c9b6e 100644
--- a/crypto/evp/cmeth_lib.c
+++ b/crypto/evp/cmeth_lib.c
@@ -55,6 +55,7 @@ void EVP_CIPHER_meth_free(EVP_CIPHER *cipher)
         if (i > 0)
             return;
         ossl_provider_free(cipher->prov);
+        OPENSSL_free(cipher->name);
         CRYPTO_THREAD_lock_free(cipher->lock);
         OPENSSL_free(cipher);
     }
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
index 65b12e3..81b51e5 100644
--- a/crypto/evp/digest.c
+++ b/crypto/evp/digest.c
@@ -577,7 +577,7 @@ int EVP_MD_CTX_ctrl(EVP_MD_CTX *ctx, int cmd, int p1, void *p2)
     return 0;
 }
 
-static void *evp_md_from_dispatch(const OSSL_DISPATCH *fns,
+static void *evp_md_from_dispatch(const char *name, const OSSL_DISPATCH *fns,
                                   OSSL_PROVIDER *prov)
 {
     EVP_MD *md = NULL;
@@ -587,6 +587,8 @@ static void *evp_md_from_dispatch(const OSSL_DISPATCH *fns,
     if ((md = EVP_MD_meth_new(NID_undef, NID_undef)) == NULL)
         return NULL;
 
+    md->name = OPENSSL_strdup(name);
+
     for (; fns->function_id != 0; fns++) {
         switch (fns->function_id) {
         case OSSL_FUNC_DIGEST_NEWCTX:
@@ -697,3 +699,12 @@ EVP_MD *EVP_MD_fetch(OPENSSL_CTX *ctx, const char *algorithm,
 
     return md;
 }
+
+void EVP_MD_do_all_ex(OPENSSL_CTX *libctx,
+                          void (*fn)(EVP_MD *mac, void *arg),
+                          void *arg)
+{
+    evp_generic_do_all(libctx, OSSL_OP_DIGEST,
+                       (void (*)(void *, void *))fn, arg,
+                       evp_md_from_dispatch, evp_md_free);
+}
diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c
index 3b83d11..00c9367 100644
--- a/crypto/evp/evp_enc.c
+++ b/crypto/evp/evp_enc.c
@@ -1081,7 +1081,8 @@ int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in)
     return 1;
 }
 
-static void *evp_cipher_from_dispatch(const OSSL_DISPATCH *fns,
+static void *evp_cipher_from_dispatch(const char *name,
+                                      const OSSL_DISPATCH *fns,
                                       OSSL_PROVIDER *prov)
 {
     EVP_CIPHER *cipher = NULL;
@@ -1094,6 +1095,8 @@ static void *evp_cipher_from_dispatch(const OSSL_DISPATCH *fns,
     if ((cipher = EVP_CIPHER_meth_new(0, 0, 0)) == NULL)
         return NULL;
 
+    cipher->name = OPENSSL_strdup(name);
+
     for (; fns->function_id != 0; fns++) {
         switch (fns->function_id) {
         case OSSL_FUNC_CIPHER_NEWCTX:
@@ -1212,3 +1215,12 @@ EVP_CIPHER *EVP_CIPHER_fetch(OPENSSL_CTX *ctx, const char *algorithm,
 
     return cipher;
 }
+
+void EVP_CIPHER_do_all_ex(OPENSSL_CTX *libctx,
+                          void (*fn)(EVP_CIPHER *mac, void *arg),
+                          void *arg)
+{
+    evp_generic_do_all(libctx, OSSL_OP_CIPHER,
+                       (void (*)(void *, void *))fn, arg,
+                       evp_cipher_from_dispatch, evp_cipher_free);
+}
diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c
index 0c25f0d..2a2d892 100644
--- a/crypto/evp/evp_fetch.c
+++ b/crypto/evp/evp_fetch.c
@@ -40,7 +40,8 @@ struct method_data_st {
     OPENSSL_CTX *libctx;
     const char *name;
     OSSL_METHOD_CONSTRUCT_METHOD *mcm;
-    void *(*method_from_dispatch)(const OSSL_DISPATCH *, OSSL_PROVIDER *);
+    void *(*method_from_dispatch)(const char *, const OSSL_DISPATCH *,
+                                  OSSL_PROVIDER *);
     int (*refcnt_up_method)(void *method);
     void (*destruct_method)(void *method);
 };
@@ -143,7 +144,7 @@ static void *construct_method(const char *name, const OSSL_DISPATCH *fns,
 {
     struct method_data_st *methdata = data;
 
-    return methdata->method_from_dispatch(fns, prov);
+    return methdata->method_from_dispatch(name, fns, prov);
 }
 
 static void destruct_method(void *method, void *data)
@@ -155,7 +156,8 @@ static void destruct_method(void *method, void *data)
 
 void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
                         const char *name, const char *properties,
-                        void *(*new_method)(const OSSL_DISPATCH *fns,
+                        void *(*new_method)(const char *name,
+                                            const OSSL_DISPATCH *fns,
                                             OSSL_PROVIDER *prov),
                         int (*up_ref_method)(void *),
                         void (*free_method)(void *))
@@ -234,3 +236,42 @@ int EVP_set_default_properties(OPENSSL_CTX *libctx, const char *propq)
     EVPerr(EVP_F_EVP_SET_DEFAULT_PROPERTIES, ERR_R_INTERNAL_ERROR);
     return 0;
 }
+
+struct do_all_data_st {
+    void (*user_fn)(void *method, void *arg);
+    void *user_arg;
+    void *(*new_method)(const char *name, const OSSL_DISPATCH *fns,
+                        OSSL_PROVIDER *prov);
+    void (*free_method)(void *);
+};
+
+static void do_one(OSSL_PROVIDER *provider, const OSSL_ALGORITHM *algo,
+                   int no_store, void *vdata)
+{
+    struct do_all_data_st *data = vdata;
+    void *method = data->new_method(algo->algorithm_name,
+                                    algo->implementation, provider);
+
+    if (method != NULL) {
+        data->user_fn(method, data->user_arg);
+        data->free_method(method);
+    }
+}
+
+
+void evp_generic_do_all(OPENSSL_CTX *libctx, int operation_id,
+                        void (*user_fn)(void *method, void *arg),
+                        void *user_arg,
+                        void *(*new_method)(const char *name,
+                                            const OSSL_DISPATCH *fns,
+                                            OSSL_PROVIDER *prov),
+                        void (*free_method)(void *))
+{
+    struct do_all_data_st data;
+
+    data.new_method = new_method;
+    data.free_method = free_method;
+    data.user_fn = user_fn;
+    data.user_arg = user_arg;
+    ossl_algorithm_do_all(libctx, operation_id, NULL, do_one, &data);
+}
diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c
index 9d1d197..b0de4bb 100644
--- a/crypto/evp/evp_lib.c
+++ b/crypto/evp/evp_lib.c
@@ -396,6 +396,22 @@ int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx)
     return ctx->cipher->nid;
 }
 
+const char *EVP_CIPHER_name(const EVP_CIPHER *cipher)
+{
+    if (cipher->prov != NULL)
+        return cipher->name;
+#ifndef FIPS_MODE
+    return OBJ_nid2sn(EVP_CIPHER_nid(cipher));
+#else
+    return NULL;
+#endif
+}
+
+const OSSL_PROVIDER *EVP_CIPHER_provider(const EVP_CIPHER *cipher)
+{
+    return cipher->prov;
+}
+
 int EVP_CIPHER_mode(const EVP_CIPHER *cipher)
 {
     int v = EVP_CIPHER_flags(cipher) & EVP_CIPH_MODE;
@@ -407,6 +423,22 @@ int EVP_CIPHER_mode(const EVP_CIPHER *cipher)
 }
 
 
+const char *EVP_MD_name(const EVP_MD *md)
+{
+    if (md->prov != NULL)
+        return md->name;
+#ifndef FIPS_MODE
+    return OBJ_nid2sn(EVP_MD_nid(md));
+#else
+    return NULL;
+#endif
+}
+
+const OSSL_PROVIDER *EVP_MD_provider(const EVP_MD *md)
+{
+    return md->prov;
+}
+
 int EVP_MD_block_size(const EVP_MD *md)
 {
     if (md == NULL) {
@@ -494,6 +526,7 @@ void EVP_MD_meth_free(EVP_MD *md)
         if (i > 0)
             return;
         ossl_provider_free(md->prov);
+        OPENSSL_free(md->name);
         CRYPTO_THREAD_lock_free(md->lock);
         OPENSSL_free(md);
     }
diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h
index 54f9e08..b56d412 100644
--- a/crypto/evp/evp_locl.h
+++ b/crypto/evp/evp_locl.h
@@ -91,10 +91,18 @@ int is_partially_overlapping(const void *ptr1, const void *ptr2, int len);
 
 void *evp_generic_fetch(OPENSSL_CTX *ctx, int operation_id,
                         const char *algorithm, const char *properties,
-                        void *(*new_method)(const OSSL_DISPATCH *fns,
+                        void *(*new_method)(const char *name,
+                                            const OSSL_DISPATCH *fns,
                                             OSSL_PROVIDER *prov),
                         int (*up_ref_method)(void *),
                         void (*free_method)(void *));
+void evp_generic_do_all(OPENSSL_CTX *libctx, int operation_id,
+                        void (*user_fn)(void *method, void *arg),
+                        void *user_arg,
+                        void *(*new_method)(const char *name,
+                                            const OSSL_DISPATCH *fns,
+                                            OSSL_PROVIDER *prov),
+                        void (*free_method)(void *));
 
 /* Helper functions to avoid duplicating code */
 
diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h
index da4ae0f..4cda76b 100644
--- a/crypto/include/internal/evp_int.h
+++ b/crypto/include/internal/evp_int.h
@@ -196,6 +196,7 @@ struct evp_md_st {
 
     /* New structure members */
     /* TODO(3.0): Remove above comment when legacy has gone */
+    char *name;
     OSSL_PROVIDER *prov;
     CRYPTO_REF_COUNT refcnt;
     CRYPTO_RWLOCK *lock;
@@ -246,6 +247,7 @@ struct evp_cipher_st {
 
     /* New structure members */
     /* TODO(3.0): Remove above comment when legacy has gone */
+    char *name;
     OSSL_PROVIDER *prov;
     CRYPTO_REF_COUNT refcnt;
     CRYPTO_RWLOCK *lock;
diff --git a/crypto/provider.c b/crypto/provider.c
index 4e21bfe..8c9c6da 100644
--- a/crypto/provider.c
+++ b/crypto/provider.c
@@ -68,3 +68,8 @@ int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *libctx, const char *name,
 
     return 1;
 }
+
+const char *OSSL_PROVIDER_name(const OSSL_PROVIDER *prov)
+{
+    return ossl_provider_name(prov);
+}
diff --git a/doc/internal/man3/ossl_algorithm_do_all.pod b/doc/internal/man3/ossl_algorithm_do_all.pod
new file mode 100644
index 0000000..4119af5
--- /dev/null
+++ b/doc/internal/man3/ossl_algorithm_do_all.pod
@@ -0,0 +1,63 @@
+=pod
+
+=head1 NAME
+
+ossl_algorithm_do_all - generic algorithm implementation iterator
+
+=head1 SYNOPSIS
+
+ void ossl_algorithm_do_all(OPENSSL_CTX *libctx, int operation_id,
+                            OSSL_PROVIDER *provider,
+                            void (*fn)(OSSL_PROVIDER *provider,
+                                       const OSSL_ALGORITHM *algo,
+                                       int no_store, void *data),
+                            void *data)
+
+=head1 DESCRIPTION
+
+ossl_algorithm_do_all() looks up every algorithm it can find, using
+the implementation query operation, given a library context I<libctx>,
+an operation identity I<operation_id> and a provider I<provider>.
+I<libctx> may be NULL to signify that the default library context is
+used.
+I<operation_id> may be zero to signify that all kinds of operations
+may be looked up.
+I<provider> may be NULL to signify that all loaded providers will be
+queried.
+
+For each implementation found, the function I<fn> is called with the
+I<provider> for the implementation, the algorithm descriptor I<algo>,
+the flag I<no_store> indicating whether the algorithm descriptor may
+be remembered or not, and the caller I<data> that was passed to
+ossl_algorithm_do_all().
+
+=head1 RETURN VALUES
+
+ossl_algorithm_do_all() doesn't return any value.
+
+=head1 NOTES
+
+The functions described here are mainly useful for discovery, and
+possibly display of what has been discovered, for example an
+application that wants to display the loaded providers and what they
+may offer, but also for constructors, such as
+L<ossl_construct_method(3)>.
+
+=head1 SEE ALSO
+
+L<ossl_construct_method(3)>, L<EVP_MAC_do_all(3)>
+
+=head1 HISTORY
+
+This functionality was added to OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use this
+file except in compliance with the License.  You can obtain a copy in the file
+LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/EVP_DigestInit.pod b/doc/man3/EVP_DigestInit.pod
index bc10fa3..5ca0563 100644
--- a/doc/man3/EVP_DigestInit.pod
+++ b/doc/man3/EVP_DigestInit.pod
@@ -7,7 +7,9 @@ EVP_MD_CTX_copy_ex, EVP_MD_CTX_ctrl, EVP_MD_CTX_set_params, EVP_MD_CTX_get_param
 EVP_MD_CTX_set_flags, EVP_MD_CTX_clear_flags, EVP_MD_CTX_test_flags,
 EVP_Digest, EVP_DigestInit_ex, EVP_DigestInit, EVP_DigestUpdate,
 EVP_DigestFinal_ex, EVP_DigestFinalXOF, EVP_DigestFinal,
+EVP_MD_name,
 EVP_MD_type, EVP_MD_pkey_type, EVP_MD_size, EVP_MD_block_size, EVP_MD_flags,
+EVP_MD_CTX_name,
 EVP_MD_CTX_md, EVP_MD_CTX_type, EVP_MD_CTX_size, EVP_MD_CTX_block_size,
 EVP_MD_CTX_md_data, EVP_MD_CTX_update_fn, EVP_MD_CTX_set_update_fn,
 EVP_md_null,
@@ -42,6 +44,7 @@ EVP_MD_CTX_pkey_ctx, EVP_MD_CTX_set_pkey_ctx - EVP digest routines
 
  int EVP_MD_CTX_copy(EVP_MD_CTX *out, EVP_MD_CTX *in);
 
+ const char *EVP_MD_name(const EVP_MD *md);
  int EVP_MD_type(const EVP_MD *md);
  int EVP_MD_pkey_type(const EVP_MD *md);
  int EVP_MD_size(const EVP_MD *md);
@@ -49,6 +52,8 @@ EVP_MD_CTX_pkey_ctx, EVP_MD_CTX_set_pkey_ctx - EVP digest routines
  unsigned long EVP_MD_flags(const EVP_MD *md);
 
  const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx);
+ const char *EVP_MD_CTX_name(const EVP_MD_CTX *ctx);
+ const OSSL_PROVIDER *EVP_MD_provider(const EVP_MD *md);
  int EVP_MD_CTX_size(const EVP_MD *ctx);
  int EVP_MD_CTX_block_size(const EVP_MD *ctx);
  int EVP_MD_CTX_type(const EVP_MD *ctx);
@@ -170,6 +175,16 @@ automatically cleaned up.
 Similar to EVP_MD_CTX_copy_ex() except the destination B<out> does not have to
 be initialized.
 
+=item EVP_MD_name(),
+EVP_MD_CTX_name()
+
+Return the name of the given message digest.
+
+=item EVP_CIPHER_provider()
+
+returns a B<OSSL_PROVIDER> pointer to the provider that implements the given
+B<EVP_MD>.
+
 =item EVP_MD_size(),
 EVP_MD_CTX_size()
 
@@ -415,9 +430,9 @@ implementations of digests to be specified.
 If digest contexts are not cleaned up after use,
 memory leaks will occur.
 
-EVP_MD_CTX_size(), EVP_MD_CTX_block_size(), EVP_MD_CTX_type(),
-EVP_get_digestbynid() and EVP_get_digestbyobj() are defined as
-macros.
+EVP_MD_CTX_name(), EVP_MD_CTX_size(), EVP_MD_CTX_block_size(),
+EVP_MD_CTX_type(), EVP_get_digestbynid() and EVP_get_digestbyobj() are defined
+as macros.
 
 EVP_MD_CTX_ctrl() sends commands to message digests for additional configuration
 or control.
diff --git a/doc/man3/EVP_EncryptInit.pod b/doc/man3/EVP_EncryptInit.pod
index 3c2e36b..e47d9e7 100644
--- a/doc/man3/EVP_EncryptInit.pod
+++ b/doc/man3/EVP_EncryptInit.pod
@@ -25,6 +25,7 @@ EVP_CipherFinal,
 EVP_get_cipherbyname,
 EVP_get_cipherbynid,
 EVP_get_cipherbyobj,
+EVP_CIPHER_name,
 EVP_CIPHER_nid,
 EVP_CIPHER_block_size,
 EVP_CIPHER_key_length,
@@ -33,6 +34,7 @@ EVP_CIPHER_flags,
 EVP_CIPHER_mode,
 EVP_CIPHER_type,
 EVP_CIPHER_CTX_cipher,
+EVP_CIPHER_CTX_name,
 EVP_CIPHER_CTX_nid,
 EVP_CIPHER_CTX_block_size,
 EVP_CIPHER_CTX_key_length,
@@ -98,6 +100,8 @@ EVP_enc_null
  const EVP_CIPHER *EVP_get_cipherbyobj(const ASN1_OBJECT *a);
 
  int EVP_CIPHER_nid(const EVP_CIPHER *e);
+ const char *EVP_CIPHER_name(const EVP_CIPHER *cipher);
+ const OSSL_PROVIDER *EVP_CIPHER_provider(const EVP_CIPHER *cipher);
  int EVP_CIPHER_block_size(const EVP_CIPHER *e);
  int EVP_CIPHER_key_length(const EVP_CIPHER *e);
  int EVP_CIPHER_iv_length(const EVP_CIPHER *e);
@@ -107,6 +111,7 @@ EVP_enc_null
 
  const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx);
  int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx);
+ const char *EVP_CIPHER_CTX_name(const EVP_CIPHER_CTX *ctx);
  int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx);
  int EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx);
  int EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx);
@@ -243,6 +248,12 @@ IDENTIFIER as such it ignores the cipher parameters and 40 bit RC2 and
 identifier or does not have ASN1 support this function will return
 B<NID_undef>.
 
+EVP_CIPHER_name() and EVP_CIPHER_CTX_name() return the name of the passed
+cipher or context.
+
+EVP_CIPHER_provider() returns a B<OSSL_PROVIDER> pointer to the provider
+that implements the given B<EVP_CIPHER>.
+
 EVP_CIPHER_CTX_cipher() returns the B<EVP_CIPHER> structure when passed
 an B<EVP_CIPHER_CTX> structure.
 
diff --git a/doc/man3/OSSL_PROVIDER.pod b/doc/man3/OSSL_PROVIDER.pod
index 9fe2e18..4d43880 100644
--- a/doc/man3/OSSL_PROVIDER.pod
+++ b/doc/man3/OSSL_PROVIDER.pod
@@ -21,6 +21,8 @@ OSSL_PROVIDER_add_builtin - provider routines
  int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *, const char *name,
                                ossl_provider_init_fn *init_fn);
 
+ const char *OSSL_PROVIDER_name(const OSSL_PROVIDER *prov);
+
 =head1 DESCRIPTION
 
 B<OSSL_PROVIDER> is a type that holds internal information about
@@ -59,6 +61,8 @@ The caller must prepare the B<OSSL_PARAM> array before calling this
 function, and the variables acting as buffers for this parameter array
 should be filled with data when it returns successfully.
 
+OSSL_PROVIDER_name() returns the name of the given provider.
+
 =head1 RETURN VALUES
 
 OSSL_PROVIDER_add() returns 1 on success, or 0 on error.
diff --git a/include/internal/core.h b/include/internal/core.h
index 3f0cdfa..bd2f9a0 100644
--- a/include/internal/core.h
+++ b/include/internal/core.h
@@ -51,4 +51,11 @@ void *ossl_method_construct(OPENSSL_CTX *ctx, int operation_id,
                             int force_cache,
                             OSSL_METHOD_CONSTRUCT_METHOD *mcm, void *mcm_data);
 
+void ossl_algorithm_do_all(OPENSSL_CTX *libctx, int operation_id,
+                           OSSL_PROVIDER *provider,
+                           void (*fn)(OSSL_PROVIDER *provider,
+                                      const OSSL_ALGORITHM *algo,
+                                      int no_store, void *data),
+                           void *data);
+
 #endif
diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h
index 0542732..64db58e 100644
--- a/include/openssl/core_numbers.h
+++ b/include/openssl/core_numbers.h
@@ -228,6 +228,9 @@ OSSL_CORE_MAKE_FUNC(int, OP_cipher_ctx_get_params, (void *cctx,
 OSSL_CORE_MAKE_FUNC(int, OP_cipher_ctx_set_params, (void *cctx,
                                                     const OSSL_PARAM params[]))
 
+/* Highest known operation number */
+# define OSSL_OP__HIGHEST                            2
+
 # ifdef __cplusplus
 }
 # endif
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index e781ebe..515f292 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -449,7 +449,8 @@ typedef int (EVP_PBE_KEYGEN) (EVP_CIPHER_CTX *ctx, const char *pass,
 
 int EVP_MD_type(const EVP_MD *md);
 # define EVP_MD_nid(e)                   EVP_MD_type(e)
-# define EVP_MD_name(e)                  OBJ_nid2sn(EVP_MD_nid(e))
+const char *EVP_MD_name(const EVP_MD *md);
+const OSSL_PROVIDER *EVP_MD_provider(const EVP_MD *md);
 int EVP_MD_pkey_type(const EVP_MD *md);
 int EVP_MD_size(const EVP_MD *md);
 int EVP_MD_block_size(const EVP_MD *md);
@@ -461,6 +462,7 @@ int (*EVP_MD_CTX_update_fn(EVP_MD_CTX *ctx))(EVP_MD_CTX *ctx,
 void EVP_MD_CTX_set_update_fn(EVP_MD_CTX *ctx,
                               int (*update) (EVP_MD_CTX *ctx,
                                              const void *data, size_t count));
+# define EVP_MD_CTX_name(e)              EVP_MD_name(EVP_MD_CTX_md(e))
 # define EVP_MD_CTX_size(e)              EVP_MD_size(EVP_MD_CTX_md(e))
 # define EVP_MD_CTX_block_size(e)        EVP_MD_block_size(EVP_MD_CTX_md(e))
 # define EVP_MD_CTX_type(e)              EVP_MD_type(EVP_MD_CTX_md(e))
@@ -469,7 +471,8 @@ void EVP_MD_CTX_set_pkey_ctx(EVP_MD_CTX *ctx, EVP_PKEY_CTX *pctx);
 void *EVP_MD_CTX_md_data(const EVP_MD_CTX *ctx);
 
 int EVP_CIPHER_nid(const EVP_CIPHER *cipher);
-# define EVP_CIPHER_name(e)              OBJ_nid2sn(EVP_CIPHER_nid(e))
+const char *EVP_CIPHER_name(const EVP_CIPHER *cipher);
+const OSSL_PROVIDER *EVP_CIPHER_provider(const EVP_CIPHER *cipher);
 int EVP_CIPHER_block_size(const EVP_CIPHER *cipher);
 int EVP_CIPHER_impl_ctx_size(const EVP_CIPHER *cipher);
 int EVP_CIPHER_key_length(const EVP_CIPHER *cipher);
@@ -496,6 +499,7 @@ void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx);
 void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data);
 void *EVP_CIPHER_CTX_get_cipher_data(const EVP_CIPHER_CTX *ctx);
 void *EVP_CIPHER_CTX_set_cipher_data(EVP_CIPHER_CTX *ctx, void *cipher_data);
+# define EVP_CIPHER_CTX_name(c)         EVP_CIPHER_name(EVP_CIPHER_CTX_cipher(c))
 # define EVP_CIPHER_CTX_type(c)         EVP_CIPHER_type(EVP_CIPHER_CTX_cipher(c))
 # if !OPENSSL_API_1_1_0
 #  define EVP_CIPHER_CTX_flags(c)       EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(c))
@@ -991,6 +995,9 @@ void EVP_CIPHER_do_all(void (*fn) (const EVP_CIPHER *ciph,
 void EVP_CIPHER_do_all_sorted(void (*fn)
                                (const EVP_CIPHER *ciph, const char *from,
                                 const char *to, void *x), void *arg);
+void EVP_CIPHER_do_all_ex(OPENSSL_CTX *libctx,
+                          void (*fn)(EVP_CIPHER *mac, void *arg),
+                          void *arg);
 
 void EVP_MD_do_all(void (*fn) (const EVP_MD *ciph,
                                const char *from, const char *to, void *x),
@@ -998,6 +1005,9 @@ void EVP_MD_do_all(void (*fn) (const EVP_MD *ciph,
 void EVP_MD_do_all_sorted(void (*fn)
                            (const EVP_MD *ciph, const char *from,
                             const char *to, void *x), void *arg);
+void EVP_MD_do_all_ex(OPENSSL_CTX *libctx,
+                      void (*fn)(EVP_MD *mac, void *arg),
+                      void *arg);
 
 /* MAC stuff */
 
diff --git a/include/openssl/provider.h b/include/openssl/provider.h
index c7f6664..722e83b 100644
--- a/include/openssl/provider.h
+++ b/include/openssl/provider.h
@@ -27,6 +27,9 @@ int OSSL_PROVIDER_get_params(const OSSL_PROVIDER *prov, OSSL_PARAM params[]);
 int OSSL_PROVIDER_add_builtin(OPENSSL_CTX *, const char *name,
                               OSSL_provider_init_fn *init_fn);
 
+/* Information */
+const char *OSSL_PROVIDER_name(const OSSL_PROVIDER *prov);
+
 # ifdef __cplusplus
 }
 # endif
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 49d2f22..b36ba11 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4678,3 +4678,10 @@ BN_rand_ex                              4783	3_0_0	EXIST::FUNCTION:
 BN_priv_rand_ex                         4784	3_0_0	EXIST::FUNCTION:
 BN_rand_range_ex                        4785	3_0_0	EXIST::FUNCTION:
 BN_priv_rand_range_ex                   4786	3_0_0	EXIST::FUNCTION:
+EVP_MD_name                             4787	3_0_0	EXIST::FUNCTION:
+EVP_CIPHER_name                         4788	3_0_0	EXIST::FUNCTION:
+EVP_MD_provider                         4789	3_0_0	EXIST::FUNCTION:
+EVP_CIPHER_provider                     4790	3_0_0	EXIST::FUNCTION:
+OSSL_PROVIDER_name                      4791	3_0_0	EXIST::FUNCTION:
+EVP_CIPHER_do_all_ex                    4792	3_0_0	EXIST::FUNCTION:
+EVP_MD_do_all_ex                        4793	3_0_0	EXIST::FUNCTION:


More information about the openssl-commits mailing list