[openssl] master update

Richard Levitte levitte at openssl.org
Thu Sep 19 12:58:24 UTC 2019


The branch master has been updated
       via  7cfa1717b812a126ce6f8e4cc32139164c89d789 (commit)
       via  f7c16d48a945e80f22f6f02550ee3fe14edb52fa (commit)
      from  f8c0218f09e190a2efb28302f6c9737efe151d27 (commit)


- Log -----------------------------------------------------------------
commit 7cfa1717b812a126ce6f8e4cc32139164c89d789
Author: Richard Levitte <levitte at openssl.org>
Date:   Sat Sep 14 16:35:08 2019 +0200

    Modify providers that keep track of underlying algorithms
    
    With some provider implementations, there are underlying ciphers,
    digests and macs.  For some of them, the name was retrieved from the
    method, but since the methods do not store those any more, we add
    different mechanics.
    
    For code that needs to pass on the name of a cipher or diges via
    parameters, we simply locally store the name that was used when
    fetching said cipher or digest.  This will ensure that any underlying
    code that needs to fetch that same cipher or digest does so with the
    exact same name instead of any random name from the set of names
    associated with the algorithm.
    
    For code that needs to check what kind of algorithm was passed, we
    provide EVP_{type}_is_a(), that returns true if the given method has
    the given name as one of its names.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/9897)

commit f7c16d48a945e80f22f6f02550ee3fe14edb52fa
Author: Richard Levitte <levitte at openssl.org>
Date:   Sat Sep 14 16:22:19 2019 +0200

    In provider implemented methods, save the name number, not the name string
    
    Multiple names per implementation is already supported in the namemap,
    but hasn't been used yet.  However, as soon as we have multiple names,
    we will get an issue with what name should be saved in the method.
    
    The solution is to not save the name itself, but rather the number
    it's associated with.  This number is supposed to be unique for each
    set of names, and we assume that algorithm names are globally unique,
    i.e. there can be no name overlap between different algorithm types.
    
    Incidently, it was also found that the 'get' function used by
    ossl_construct_method() doesn't need all the parameters it was given;
    most of what it needs, it can now get through the data structure given
    by the caller of ossl_construct_method().  As a consequence,
    ossl_construct_method() itself doesn't need all the parameters it was
    given either.
    
    There are some added internal functions that are expected to disappear
    as soon as legacy code is removed, such as evp_first_name() and
    ossl_namemap_num2name().
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/9897)

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

Summary of changes:
 crypto/core_fetch.c                               |   8 +-
 crypto/core_namemap.c                             |  26 +++
 crypto/evp/digest.c                               |  27 +--
 crypto/evp/evp_enc.c                              |  26 +--
 crypto/evp/evp_fetch.c                            | 208 +++++++++++++++++-----
 crypto/evp/evp_lib.c                              |   9 +-
 crypto/evp/evp_locl.h                             |  29 ++-
 crypto/evp/exchange.c                             |  12 +-
 crypto/evp/kdf_lib.c                              |   2 +-
 crypto/evp/kdf_meth.c                             |  12 +-
 crypto/evp/keymgmt_meth.c                         |  32 ++--
 crypto/evp/mac_meth.c                             |  19 +-
 crypto/evp/pkey_mac.c                             |   4 +-
 crypto/evp/pmeth_fn.c                             |  12 +-
 crypto/include/internal/evp_int.h                 |   8 +-
 doc/internal/man3/evp_generic_fetch.pod           |  49 +++--
 doc/internal/man3/ossl_method_construct.pod       |  26 ++-
 doc/man3/EVP_EncryptInit.pod                      |   5 +
 doc/man3/EVP_MAC.pod                              |  10 +-
 include/internal/core.h                           |   5 +-
 include/internal/namemap.h                        |   2 +
 include/openssl/evp.h                             |   2 +
 providers/common/include/internal/provider_util.h |  16 +-
 providers/common/kdfs/sskdf.c                     |  10 +-
 providers/common/provider_util.c                  |  15 ++
 util/libcrypto.num                                |   2 +
 26 files changed, 403 insertions(+), 173 deletions(-)

diff --git a/crypto/core_fetch.c b/crypto/core_fetch.c
index 6e4414d831..1e0d82fb61 100644
--- a/crypto/core_fetch.c
+++ b/crypto/core_fetch.c
@@ -66,15 +66,12 @@ static void ossl_method_construct_this(OSSL_PROVIDER *provider,
 }
 
 void *ossl_method_construct(OPENSSL_CTX *libctx, int operation_id,
-                            const char *name, const char *propquery,
                             int force_store,
                             OSSL_METHOD_CONSTRUCT_METHOD *mcm, void *mcm_data)
 {
     void *method = NULL;
 
-    if ((method =
-         mcm->get(libctx, NULL, operation_id, name, propquery, mcm_data))
-        == NULL) {
+    if ((method = mcm->get(libctx, NULL, mcm_data)) == NULL) {
         struct construct_data_st cbdata;
 
         /*
@@ -92,8 +89,7 @@ void *ossl_method_construct(OPENSSL_CTX *libctx, int operation_id,
         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);
+        method = mcm->get(libctx, cbdata.store, mcm_data);
         mcm->dealloc_tmp_store(cbdata.store);
     }
 
diff --git a/crypto/core_namemap.c b/crypto/core_namemap.c
index d4c9419044..cf5f1e54c3 100644
--- a/crypto/core_namemap.c
+++ b/crypto/core_namemap.c
@@ -173,6 +173,32 @@ int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name)
     return number;
 }
 
+struct num2name_data_st {
+    size_t idx;                  /* Countdown */
+    const char *name;            /* Result */
+};
+
+static void do_num2name(const char *name, void *vdata)
+{
+    struct num2name_data_st *data = vdata;
+
+    if (data->idx > 0)
+        data->idx--;
+    else if (data->name == NULL)
+        data->name = name;
+}
+
+const char *ossl_namemap_num2name(const OSSL_NAMEMAP *namemap, int number,
+                                  size_t idx)
+{
+    struct num2name_data_st data;
+
+    data.idx = idx;
+    data.name = NULL;
+    ossl_namemap_doall_names(namemap, number, do_num2name, &data);
+    return data.name;
+}
+
 int ossl_namemap_add(OSSL_NAMEMAP *namemap, int number, const char *name)
 {
     NAMENUM_ENTRY *namenum = NULL;
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
index 0da934a691..f39a443c89 100644
--- a/crypto/evp/digest.c
+++ b/crypto/evp/digest.c
@@ -636,29 +636,31 @@ EVP_MD *evp_md_new(void)
     return md;
 }
 
-static void *evp_md_from_dispatch(const char *name, const OSSL_DISPATCH *fns,
+static void *evp_md_from_dispatch(int name_id,
+                                  const OSSL_DISPATCH *fns,
                                   OSSL_PROVIDER *prov, void *unused)
 {
     EVP_MD *md = NULL;
     int fncnt = 0;
 
     /* EVP_MD_fetch() will set the legacy NID if available */
-    if ((md = evp_md_new()) == NULL
-        || (md->name = OPENSSL_strdup(name)) == NULL) {
-        EVP_MD_free(md);
+    if ((md = evp_md_new()) == NULL) {
         EVPerr(0, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
+    md->name_id = name_id;
 
 #ifndef FIPS_MODE
-    /*
-     * FIPS module note: since internal fetches will be entirely
-     * provider based, we know that none of its code depends on legacy
-     * NIDs or any functionality that use them.
-     *
-     * TODO(3.x) get rid of the need for legacy NIDs
-     */
-    md->type = OBJ_sn2nid(name);
+    {
+        /*
+         * FIPS module note: since internal fetches will be entirely
+         * provider based, we know that none of its code depends on legacy
+         * NIDs or any functionality that use them.
+         *
+         * TODO(3.x) get rid of the need for legacy NIDs
+         */
+        md->type = OBJ_sn2nid(evp_first_name(prov, name_id));
+    }
 #endif
 
     for (; fns->function_id != 0; fns++) {
@@ -789,7 +791,6 @@ void EVP_MD_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_enc.c b/crypto/evp/evp_enc.c
index f2511a2b28..6e509b2d13 100644
--- a/crypto/evp/evp_enc.c
+++ b/crypto/evp/evp_enc.c
@@ -1281,7 +1281,7 @@ EVP_CIPHER *evp_cipher_new(void)
     return cipher;
 }
 
-static void *evp_cipher_from_dispatch(const char *name,
+static void *evp_cipher_from_dispatch(const int name_id,
                                       const OSSL_DISPATCH *fns,
                                       OSSL_PROVIDER *prov,
                                       void *unused)
@@ -1289,22 +1289,23 @@ static void *evp_cipher_from_dispatch(const char *name,
     EVP_CIPHER *cipher = NULL;
     int fnciphcnt = 0, fnctxcnt = 0;
 
-    if ((cipher = evp_cipher_new()) == NULL
-        || (cipher->name = OPENSSL_strdup(name)) == NULL) {
-        EVP_CIPHER_free(cipher);
+    if ((cipher = evp_cipher_new()) == NULL) {
         EVPerr(0, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
+    cipher->name_id = name_id;
 
 #ifndef FIPS_MODE
-    /*
-     * FIPS module note: since internal fetches will be entirely
-     * provider based, we know that none of its code depends on legacy
-     * NIDs or any functionality that use them.
-     *
-     * TODO(3.x) get rid of the need for legacy NIDs
-     */
-    cipher->nid = OBJ_sn2nid(name);
+    {
+        /*
+         * FIPS module note: since internal fetches will be entirely
+         * provider based, we know that none of its code depends on legacy
+         * NIDs or any functionality that use them.
+         *
+         * TODO(3.x) get rid of the need for legacy NIDs
+         */
+        cipher->nid = OBJ_sn2nid(evp_first_name(prov, name_id));
+    }
 #endif
 
     for (; fns->function_id != 0; fns++) {
@@ -1449,7 +1450,6 @@ void EVP_CIPHER_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/evp_fetch.c b/crypto/evp/evp_fetch.c
index 662195e4de..6e31af79f2 100644
--- a/crypto/evp/evp_fetch.c
+++ b/crypto/evp/evp_fetch.c
@@ -15,6 +15,7 @@
 #include "internal/thread_once.h"
 #include "internal/property.h"
 #include "internal/core.h"
+#include "internal/provider.h"
 #include "internal/namemap.h"
 #include "internal/evp_int.h"    /* evp_locl.h needs it */
 #include "evp_locl.h"
@@ -38,9 +39,12 @@ static const OPENSSL_CTX_METHOD default_method_store_method = {
 /* Data to be passed through ossl_method_construct() */
 struct method_data_st {
     OPENSSL_CTX *libctx;
-    const char *name;
     OSSL_METHOD_CONSTRUCT_METHOD *mcm;
-    void *(*method_from_dispatch)(const char *, const OSSL_DISPATCH *,
+    int operation_id;            /* For get_method_from_store() */
+    int name_id;                 /* For get_method_from_store() */
+    const char *name;            /* For get_method_from_store() */
+    const char *propquery;       /* For get_method_from_store() */
+    void *(*method_from_dispatch)(int name_id, const OSSL_DISPATCH *,
                                   OSSL_PROVIDER *, void *);
     void *method_data;
     int (*refcnt_up_method)(void *method);
@@ -78,7 +82,7 @@ static OSSL_METHOD_STORE *get_default_method_store(OPENSSL_CTX *libctx)
  * |      name identity     | op id  |
  * +------------------------+--------+
  */
-static uint32_t method_id(unsigned int operation_id, unsigned int name_id)
+static uint32_t method_id(unsigned int operation_id, int name_id)
 {
     if (!ossl_assert(name_id < (1 << 24) || operation_id < (1 << 8))
         || !ossl_assert(name_id > 0 && operation_id > 0))
@@ -87,25 +91,36 @@ static uint32_t method_id(unsigned int operation_id, unsigned int name_id)
 }
 
 static void *get_method_from_store(OPENSSL_CTX *libctx, void *store,
-                                   int operation_id, const char *name,
-                                   const char *propquery, void *data)
+                                   void *data)
 {
     struct method_data_st *methdata = data;
     void *method = NULL;
-    OSSL_NAMEMAP *namemap;
-    int nameid;
-    uint32_t methid;
+    int name_id;
+    uint32_t meth_id;
 
-    if (store == NULL
-        && (store = get_default_method_store(libctx)) == NULL)
+    /*
+     * get_method_from_store() is only called to try and get the method
+     * that evp_generic_fetch() is asking for, and the operation id as
+     * well as the name or name id are passed via methdata.
+     */
+    if ((name_id = methdata->name_id) == 0) {
+        OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
+
+        if (namemap == 0)
+            return NULL;
+        name_id = ossl_namemap_name2num(namemap, methdata->name);
+    }
+
+    if (name_id == 0
+        || (meth_id = method_id(methdata->operation_id, name_id)) == 0)
         return NULL;
 
-    if ((namemap = ossl_namemap_stored(libctx)) == NULL
-        || (nameid = ossl_namemap_name2num(namemap, name)) == 0
-        || (methid = method_id(operation_id, nameid)) == 0)
+    if (store == NULL
+        && (store = get_default_method_store(libctx)) == NULL)
         return NULL;
 
-    (void)ossl_method_store_fetch(store, methid, propquery, &method);
+    (void)ossl_method_store_fetch(store, meth_id, methdata->propquery,
+                                  &method);
 
     if (method != NULL
         && !methdata->refcnt_up_method(method)) {
@@ -121,29 +136,52 @@ static int put_method_in_store(OPENSSL_CTX *libctx, void *store,
 {
     struct method_data_st *methdata = data;
     OSSL_NAMEMAP *namemap;
-    int nameid;
-    uint32_t methid;
+    int name_id;
+    uint32_t meth_id;
 
-    if ((namemap = ossl_namemap_stored(methdata->libctx)) == NULL
-        || (nameid = ossl_namemap_add(namemap, 0, name)) == 0
-        || (methid = method_id(operation_id, nameid)) == 0)
+    /*
+     * put_method_in_store() is only called with a method that was
+     * successfully created by construct_method() below, which means
+     * the name should already be stored in the namemap, so just use it.
+     */
+    if ((namemap = ossl_namemap_stored(libctx)) == NULL
+        || (name_id = ossl_namemap_name2num(namemap, name)) == 0
+        || (meth_id = method_id(operation_id, name_id)) == 0)
         return 0;
 
     if (store == NULL
         && (store = get_default_method_store(libctx)) == NULL)
         return 0;
 
-    return ossl_method_store_add(store, prov, methid, propdef, method,
+    return ossl_method_store_add(store, prov, meth_id, propdef, method,
                                  methdata->refcnt_up_method,
                                  methdata->destruct_method);
 }
 
+/*
+ * The core fetching functionality passes the name of the implementation.
+ * This function is responsible to getting an identity number for it.
+ */
 static void *construct_method(const char *name, const OSSL_DISPATCH *fns,
                               OSSL_PROVIDER *prov, void *data)
 {
+    /*
+     * This function is only called if get_method_from_store() returned
+     * NULL, so it's safe to say that of all the spots to create a new
+     * namemap entry, this is it.  Should the name already exist there, we
+     * know that ossl_namemap_add() will return its corresponding number.
+     *
+     * TODO(3.0): If this function gets an array of names instead of just
+     * one, we need to check through all the names to see if at least one
+     * of them has an associated number, and use that.  If several names
+     * have associated numbers that differ from each other, it's an error.
+     */
     struct method_data_st *methdata = data;
+    OPENSSL_CTX *libctx = ossl_provider_library_context(prov);
+    OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
+    int name_id = ossl_namemap_add(namemap, 0, name);
 
-    return methdata->method_from_dispatch(name, fns, prov,
+    return methdata->method_from_dispatch(name_id, fns, prov,
                                           methdata->method_data);
 }
 
@@ -154,20 +192,20 @@ static void destruct_method(void *method, void *data)
     methdata->destruct_method(method);
 }
 
-void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
-                        const char *name, const char *properties,
-                        void *(*new_method)(const char *name,
-                                            const OSSL_DISPATCH *fns,
-                                            OSSL_PROVIDER *prov,
-                                            void *method_data),
-                        void *method_data,
-                        int (*up_ref_method)(void *),
-                        void (*free_method)(void *))
+static void *inner_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
+                                 int name_id, const char *name,
+                                 const char *properties,
+                                 void *(*new_method)(int name_id,
+                                                     const OSSL_DISPATCH *fns,
+                                                     OSSL_PROVIDER *prov,
+                                                     void *method_data),
+                                 void *method_data,
+                                 int (*up_ref_method)(void *),
+                                 void (*free_method)(void *))
 {
     OSSL_METHOD_STORE *store = get_default_method_store(libctx);
     OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
-    int nameid = 0;
-    uint32_t methid = 0;
+    uint32_t meth_id = 0;
     void *method = NULL;
 
     if (store == NULL || namemap == NULL)
@@ -181,17 +219,28 @@ void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
         return NULL;
 
     /*
+     * If we have been passed neither a name_id or a name, we have an
+     * internal programming error.
+     */
+    if (!ossl_assert(name_id != 0 || name != NULL))
+        return NULL;
+
+    /* If we haven't received a name id yet, try to get one for the name */
+    if (name_id == 0)
+        name_id = ossl_namemap_name2num(namemap, name);
+
+    /*
+     * If we have a name id, calculate a method id with method_id().
+     *
      * method_id returns 0 if we have too many operations (more than
      * about 2^8) or too many names (more than about 2^24).  In that
      * case, we can't create any new method.
      */
-    if ((nameid = ossl_namemap_name2num(namemap, name)) != 0
-        && (methid = method_id(operation_id, nameid)) == 0)
+    if (name_id != 0 && (meth_id = method_id(operation_id, name_id)) == 0)
         return NULL;
 
-    if (nameid == 0
-        || !ossl_method_store_cache_get(store, methid, properties,
-                                        &method)) {
+    if (meth_id == 0
+        || !ossl_method_store_cache_get(store, meth_id, properties, &method)) {
         OSSL_METHOD_CONSTRUCT_METHOD mcm = {
             alloc_tmp_method_store,
             dealloc_tmp_method_store,
@@ -204,24 +253,28 @@ void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
 
         mcmdata.mcm = &mcm;
         mcmdata.libctx = libctx;
+        mcmdata.operation_id = operation_id;
+        mcmdata.name_id = name_id;
         mcmdata.name = name;
+        mcmdata.propquery = properties;
         mcmdata.method_from_dispatch = new_method;
         mcmdata.destruct_method = free_method;
         mcmdata.refcnt_up_method = up_ref_method;
         mcmdata.destruct_method = free_method;
         mcmdata.method_data = method_data;
-        if ((method = ossl_method_construct(libctx, operation_id, name,
-                                            properties, 0 /* !force_cache */,
+        if ((method = ossl_method_construct(libctx, operation_id,
+                                            0 /* !force_cache */,
                                             &mcm, &mcmdata)) != NULL) {
             /*
              * If construction did create a method for us, we know that
-             * there is a correct nameid and methodid, since those have
+             * there is a correct name_id and methodid, since those have
              * already been calculated in get_method_from_store() and
              * put_method_in_store() above.
              */
-            nameid = ossl_namemap_name2num(namemap, name);
-            methid = method_id(operation_id, nameid);
-            ossl_method_store_cache_set(store, methid, properties, method);
+            if (name_id == 0)
+                name_id = ossl_namemap_name2num(namemap, name);
+            meth_id = method_id(operation_id, name_id);
+            ossl_method_store_cache_set(store, meth_id, properties, method);
         }
     } else {
         up_ref_method(method);
@@ -230,6 +283,45 @@ void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
     return method;
 }
 
+void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
+                        const char *name, const char *properties,
+                        void *(*new_method)(int name_id,
+                                            const OSSL_DISPATCH *fns,
+                                            OSSL_PROVIDER *prov,
+                                            void *method_data),
+                        void *method_data,
+                        int (*up_ref_method)(void *),
+                        void (*free_method)(void *))
+{
+    return inner_generic_fetch(libctx,
+                               operation_id, 0, name, properties,
+                               new_method, method_data,
+                               up_ref_method, free_method);
+}
+
+/*
+ * evp_generic_fetch_by_number() is special, and only returns methods for
+ * already known names, i.e. it refuses to work if no name_id can be found
+ * (it's considered an internal programming error).
+ * This is meant to be used when one method needs to fetch an associated
+ * other method.
+ */
+void *evp_generic_fetch_by_number(OPENSSL_CTX *libctx, int operation_id,
+                                  int name_id, const char *properties,
+                                  void *(*new_method)(int name_id,
+                                                      const OSSL_DISPATCH *fns,
+                                                      OSSL_PROVIDER *prov,
+                                                      void *method_data),
+                                  void *method_data,
+                                  int (*up_ref_method)(void *),
+                                  void (*free_method)(void *))
+{
+    return inner_generic_fetch(libctx,
+                               operation_id, name_id, NULL, properties,
+                               new_method, method_data,
+                               up_ref_method, free_method);
+}
+
 int EVP_set_default_properties(OPENSSL_CTX *libctx, const char *propq)
 {
     OSSL_METHOD_STORE *store = get_default_method_store(libctx);
@@ -243,7 +335,7 @@ int EVP_set_default_properties(OPENSSL_CTX *libctx, const char *propq)
 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,
+    void *(*new_method)(const int name_id, const OSSL_DISPATCH *fns,
                         OSSL_PROVIDER *prov, void *method_data);
     void (*free_method)(void *);
 };
@@ -252,8 +344,14 @@ 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, NULL);
+    OPENSSL_CTX *libctx = ossl_provider_library_context(provider);
+    OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
+    int name_id = ossl_namemap_add(namemap, 0, algo->algorithm_name);
+    void *method = NULL;
+
+    if (name_id != 0)
+        method = data->new_method(name_id, algo->implementation, provider,
+                                  NULL);
 
     if (method != NULL) {
         data->user_fn(method, data->user_arg);
@@ -264,7 +362,7 @@ static void do_one(OSSL_PROVIDER *provider, const OSSL_ALGORITHM *algo,
 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,
+                        void *(*new_method)(int name_id,
                                             const OSSL_DISPATCH *fns,
                                             OSSL_PROVIDER *prov,
                                             void *method_data),
@@ -279,3 +377,19 @@ void evp_generic_do_all(OPENSSL_CTX *libctx, int operation_id,
     data.user_arg = user_arg;
     ossl_algorithm_do_all(libctx, operation_id, method_data, do_one, &data);
 }
+
+const char *evp_first_name(OSSL_PROVIDER *prov, int name_id)
+{
+    OPENSSL_CTX *libctx = ossl_provider_library_context(prov);
+    OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
+
+    return ossl_namemap_num2name(namemap, name_id, 0);
+}
+
+int evp_is_a(OSSL_PROVIDER *prov, int number, const char *name)
+{
+    OPENSSL_CTX *libctx = ossl_provider_library_context(prov);
+    OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
+
+    return ossl_namemap_name2num(namemap, name) == number;
+}
diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c
index eeed7359a4..e48c63037e 100644
--- a/crypto/evp/evp_lib.c
+++ b/crypto/evp/evp_lib.c
@@ -448,10 +448,15 @@ int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx)
     return ctx->cipher->nid;
 }
 
+int EVP_CIPHER_is_a(const EVP_CIPHER *cipher, const char *name)
+{
+    return evp_is_a(cipher->prov, cipher->name_id, name);
+}
+
 const char *EVP_CIPHER_name(const EVP_CIPHER *cipher)
 {
     if (cipher->prov != NULL)
-        return cipher->name;
+        return evp_first_name(cipher->prov, cipher->name_id);
 #ifndef FIPS_MODE
     return OBJ_nid2sn(EVP_CIPHER_nid(cipher));
 #else
@@ -479,7 +484,7 @@ int EVP_CIPHER_mode(const EVP_CIPHER *cipher)
 const char *EVP_MD_name(const EVP_MD *md)
 {
     if (md->prov != NULL)
-        return md->name;
+        return evp_first_name(md->prov, md->name_id);
 #ifndef FIPS_MODE
     return OBJ_nid2sn(EVP_MD_nid(md));
 #else
diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h
index fd684c4b4c..ebfa3acd08 100644
--- a/crypto/evp/evp_locl.h
+++ b/crypto/evp/evp_locl.h
@@ -68,7 +68,7 @@ struct evp_kdf_ctx_st {
 struct evp_keymgmt_st {
     int id;                      /* libcrypto internal */
 
-    char *name;
+    int name_id;
     OSSL_PROVIDER *prov;
     CRYPTO_REF_COUNT refcnt;
     CRYPTO_RWLOCK *lock;
@@ -97,7 +97,7 @@ struct keymgmt_data_st {
 };
 
 struct evp_keyexch_st {
-    char *name;
+    int name_id;
     OSSL_PROVIDER *prov;
     CRYPTO_REF_COUNT refcnt;
     CRYPTO_RWLOCK *lock;
@@ -115,7 +115,7 @@ struct evp_keyexch_st {
 } /* EVP_KEYEXCH */;
 
 struct evp_signature_st {
-    char *name;
+    int name_id;
     OSSL_PROVIDER *prov;
     CRYPTO_REF_COUNT refcnt;
     CRYPTO_RWLOCK *lock;
@@ -167,24 +167,37 @@ int is_partially_overlapping(const void *ptr1, const void *ptr2, int len);
 #include <openssl/core.h>
 
 void *evp_generic_fetch(OPENSSL_CTX *ctx, int operation_id,
-                        const char *algorithm, const char *properties,
-                        void *(*new_method)(const char *name,
+                        const char *name, const char *properties,
+                        void *(*new_method)(int name_id,
                                             const OSSL_DISPATCH *fns,
                                             OSSL_PROVIDER *prov,
                                             void *method_data),
                         void *method_data,
                         int (*up_ref_method)(void *),
                         void (*free_method)(void *));
+void *evp_generic_fetch_by_number(OPENSSL_CTX *ctx, int operation_id,
+                                  int name_id, const char *properties,
+                                  void *(*new_method)(int name_id,
+                                                      const OSSL_DISPATCH *fns,
+                                                      OSSL_PROVIDER *prov,
+                                                      void *method_data),
+                                  void *method_data,
+                                  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,
+                        void *(*new_method)(int name_id,
                                             const OSSL_DISPATCH *fns,
                                             OSSL_PROVIDER *prov,
                                             void *method_data),
                         void *method_data,
                         void (*free_method)(void *));
 
+/* Internal fetchers for method types that are to be combined with others */
+EVP_KEYMGMT *evp_keymgmt_fetch_by_number(OPENSSL_CTX *ctx, int name_id,
+                                         const char *properties);
+
 /* Internal structure constructors for fetched methods */
 EVP_MD *evp_md_new(void);
 EVP_CIPHER *evp_cipher_new(void);
@@ -234,3 +247,7 @@ OSSL_PARAM *evp_pkey_to_param(EVP_PKEY *pkey, size_t *sz);
     }
 
 void evp_pkey_ctx_free_old_ops(EVP_PKEY_CTX *ctx);
+
+/* OSSL_PROVIDER * is only used to get the library context */
+const char *evp_first_name(OSSL_PROVIDER *prov, int name_id);
+int evp_is_a(OSSL_PROVIDER *prov, int number, const char *name);
diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c
index 7c61a12b3b..53a25a424e 100644
--- a/crypto/evp/exchange.c
+++ b/crypto/evp/exchange.c
@@ -32,7 +32,7 @@ static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov)
     return exchange;
 }
 
-static void *evp_keyexch_from_dispatch(const char *name,
+static void *evp_keyexch_from_dispatch(int name_id,
                                        const OSSL_DISPATCH *fns,
                                        OSSL_PROVIDER *prov,
                                        void *vkeymgmt_data)
@@ -47,8 +47,9 @@ static void *evp_keyexch_from_dispatch(const char *name,
      * provider matches.
      */
     struct keymgmt_data_st *keymgmt_data = vkeymgmt_data;
-    EVP_KEYMGMT *keymgmt = EVP_KEYMGMT_fetch(keymgmt_data->ctx, name,
-                                             keymgmt_data->properties);
+    EVP_KEYMGMT *keymgmt =
+        evp_keymgmt_fetch_by_number(keymgmt_data->ctx, name_id,
+                                    keymgmt_data->properties);
     EVP_KEYEXCH *exchange = NULL;
     int fncnt = 0, paramfncnt = 0;
 
@@ -57,12 +58,12 @@ static void *evp_keyexch_from_dispatch(const char *name,
         goto err;
     }
 
-    if ((exchange = evp_keyexch_new(prov)) == NULL
-        || (exchange->name = OPENSSL_strdup(name)) == NULL) {
+    if ((exchange = evp_keyexch_new(prov)) == NULL) {
         ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
         goto err;
     }
 
+    exchange->name_id = name_id;
     exchange->keymgmt = keymgmt;
     keymgmt = NULL;              /* avoid double free on failure below */
 
@@ -148,7 +149,6 @@ void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange)
             return;
         EVP_KEYMGMT_free(exchange->keymgmt);
         ossl_provider_free(exchange->prov);
-        OPENSSL_free(exchange->name);
         CRYPTO_THREAD_lock_free(exchange->lock);
         OPENSSL_free(exchange);
     }
diff --git a/crypto/evp/kdf_lib.c b/crypto/evp/kdf_lib.c
index 9f055a61d0..5c57cc360e 100644
--- a/crypto/evp/kdf_lib.c
+++ b/crypto/evp/kdf_lib.c
@@ -85,7 +85,7 @@ EVP_KDF_CTX *EVP_KDF_CTX_dup(const EVP_KDF_CTX *src)
 
 const char *EVP_KDF_name(const EVP_KDF *kdf)
 {
-    return kdf->name;
+    return evp_first_name(kdf->prov, kdf->name_id);
 }
 
 const OSSL_PROVIDER *EVP_KDF_provider(const EVP_KDF *kdf)
diff --git a/crypto/evp/kdf_meth.c b/crypto/evp/kdf_meth.c
index c2db212710..7bcdcc7df3 100644
--- a/crypto/evp/kdf_meth.c
+++ b/crypto/evp/kdf_meth.c
@@ -33,7 +33,6 @@ static void evp_kdf_free(void *vkdf){
         CRYPTO_DOWN_REF(&kdf->refcnt, &ref, kdf->lock);
         if (ref <= 0) {
             ossl_provider_free(kdf->prov);
-            OPENSSL_free(kdf->name);
             CRYPTO_THREAD_lock_free(kdf->lock);
             OPENSSL_free(kdf);
         }
@@ -53,18 +52,19 @@ static void *evp_kdf_new(void)
     return kdf;
 }
 
-static void *evp_kdf_from_dispatch(const char *name, const OSSL_DISPATCH *fns,
-                                   OSSL_PROVIDER *prov, void *method_data)
+static void *evp_kdf_from_dispatch(int name_id,
+                                   const OSSL_DISPATCH *fns,
+                                   OSSL_PROVIDER *prov,
+                                   void *method_data)
 {
     EVP_KDF *kdf = NULL;
     int fnkdfcnt = 0, fnctxcnt = 0;
 
-    if ((kdf = evp_kdf_new()) == NULL
-        || (kdf->name = OPENSSL_strdup(name)) == NULL) {
-        evp_kdf_free(kdf);
+    if ((kdf = evp_kdf_new()) == NULL) {
         EVPerr(0, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
+    kdf->name_id = name_id;
 
     for (; fns->function_id != 0; fns++) {
         switch (fns->function_id) {
diff --git a/crypto/evp/keymgmt_meth.c b/crypto/evp/keymgmt_meth.c
index 72ef1bdb0c..c170bd676b 100644
--- a/crypto/evp/keymgmt_meth.c
+++ b/crypto/evp/keymgmt_meth.c
@@ -33,16 +33,18 @@ static void *keymgmt_new(void)
     return keymgmt;
 }
 
-static void *keymgmt_from_dispatch(const char *name, const OSSL_DISPATCH *fns,
-                                   OSSL_PROVIDER *prov, void *unused)
+static void *keymgmt_from_dispatch(int name_id,
+                                   const OSSL_DISPATCH *fns,
+                                   OSSL_PROVIDER *prov,
+                                   void *unused)
 {
     EVP_KEYMGMT *keymgmt = NULL;
 
-    if ((keymgmt = keymgmt_new()) == NULL
-        || (keymgmt->name = OPENSSL_strdup(name)) == NULL) {
+    if ((keymgmt = keymgmt_new()) == NULL) {
         EVP_KEYMGMT_free(keymgmt);
         return NULL;
     }
+    keymgmt->name_id = name_id;
 
     for (; fns->function_id != 0; fns++) {
         switch (fns->function_id) {
@@ -151,16 +153,23 @@ static void *keymgmt_from_dispatch(const char *name, const OSSL_DISPATCH *fns,
     return keymgmt;
 }
 
+EVP_KEYMGMT *evp_keymgmt_fetch_by_number(OPENSSL_CTX *ctx, int name_id,
+                                         const char *properties)
+{
+    return evp_generic_fetch_by_number(ctx,
+                                       OSSL_OP_KEYMGMT, name_id, properties,
+                                       keymgmt_from_dispatch, NULL,
+                                       (int (*)(void *))EVP_KEYMGMT_up_ref,
+                                       (void (*)(void *))EVP_KEYMGMT_free);
+}
+
 EVP_KEYMGMT *EVP_KEYMGMT_fetch(OPENSSL_CTX *ctx, const char *algorithm,
                                const char *properties)
 {
-    EVP_KEYMGMT *keymgmt =
-        evp_generic_fetch(ctx, OSSL_OP_KEYMGMT, algorithm, properties,
-                          keymgmt_from_dispatch, NULL,
-                          (int (*)(void *))EVP_KEYMGMT_up_ref,
-                          (void (*)(void *))EVP_KEYMGMT_free);
-
-    return keymgmt;
+    return evp_generic_fetch(ctx, OSSL_OP_KEYMGMT, algorithm, properties,
+                             keymgmt_from_dispatch, NULL,
+                             (int (*)(void *))EVP_KEYMGMT_up_ref,
+                             (void (*)(void *))EVP_KEYMGMT_free);
 }
 
 int EVP_KEYMGMT_up_ref(EVP_KEYMGMT *keymgmt)
@@ -182,7 +191,6 @@ void EVP_KEYMGMT_free(EVP_KEYMGMT *keymgmt)
     if (ref > 0)
         return;
     ossl_provider_free(keymgmt->prov);
-    OPENSSL_free(keymgmt->name);
     CRYPTO_THREAD_lock_free(keymgmt->lock);
     OPENSSL_free(keymgmt);
 }
diff --git a/crypto/evp/mac_meth.c b/crypto/evp/mac_meth.c
index a317127e15..8c47a6c6e8 100644
--- a/crypto/evp/mac_meth.c
+++ b/crypto/evp/mac_meth.c
@@ -27,7 +27,6 @@ static void evp_mac_free(void *vmac)
     if (ref > 0)
         return;
     ossl_provider_free(mac->prov);
-    OPENSSL_free(mac->name);
     CRYPTO_THREAD_lock_free(mac->lock);
     OPENSSL_free(mac);
 }
@@ -47,18 +46,19 @@ static void *evp_mac_new(void)
     return mac;
 }
 
-static void *evp_mac_from_dispatch(const char *name, const OSSL_DISPATCH *fns,
-                                   OSSL_PROVIDER *prov, void *unused)
+static void *evp_mac_from_dispatch(int name_id,
+                                   const OSSL_DISPATCH *fns,
+                                   OSSL_PROVIDER *prov,
+                                   void *unused)
 {
     EVP_MAC *mac = NULL;
     int fnmaccnt = 0, fnctxcnt = 0;
 
-    if ((mac = evp_mac_new()) == NULL
-        || (mac->name = OPENSSL_strdup(name)) == NULL) {
-        EVP_MAC_free(mac);
+    if ((mac = evp_mac_new()) == NULL) {
         EVPerr(0, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
+    mac->name_id = name_id;
 
     for (; fns->function_id != 0; fns++) {
         switch (fns->function_id) {
@@ -168,9 +168,14 @@ void EVP_MAC_free(EVP_MAC *mac)
     evp_mac_free(mac);
 }
 
+int EVP_MAC_is_a(const EVP_MAC *mac, const char *name)
+{
+    return evp_is_a(mac->prov, mac->name_id, name);
+}
+
 const char *EVP_MAC_name(const EVP_MAC *mac)
 {
-    return mac->name;
+    return evp_first_name(mac->prov, mac->name_id);
 }
 
 const OSSL_PROVIDER *EVP_MAC_provider(const EVP_MAC *mac)
diff --git a/crypto/evp/pkey_mac.c b/crypto/evp/pkey_mac.c
index fc600fb845..1343e19e76 100644
--- a/crypto/evp/pkey_mac.c
+++ b/crypto/evp/pkey_mac.c
@@ -221,8 +221,8 @@ static int pkey_mac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
         && (ctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) != 0;
 
     if (set_key) {
-        if (strcmp(OBJ_nid2sn(EVP_PKEY_id(EVP_PKEY_CTX_get0_pkey(ctx))),
-                   EVP_MAC_name(EVP_MAC_CTX_mac(hctx->ctx))) != 0)
+        if (!EVP_MAC_is_a(EVP_MAC_CTX_mac(hctx->ctx),
+                          OBJ_nid2sn(EVP_PKEY_id(EVP_PKEY_CTX_get0_pkey(ctx)))))
             return 0;
         key = EVP_PKEY_get0(EVP_PKEY_CTX_get0_pkey(ctx));
         if (key == NULL)
diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c
index b46c92d633..34db48639a 100644
--- a/crypto/evp/pmeth_fn.c
+++ b/crypto/evp/pmeth_fn.c
@@ -32,7 +32,7 @@ static EVP_SIGNATURE *evp_signature_new(OSSL_PROVIDER *prov)
     return signature;
 }
 
-static void *evp_signature_from_dispatch(const char *name,
+static void *evp_signature_from_dispatch(int name_id,
                                          const OSSL_DISPATCH *fns,
                                          OSSL_PROVIDER *prov,
                                          void *vkeymgmt_data)
@@ -47,8 +47,9 @@ static void *evp_signature_from_dispatch(const char *name,
      * provider matches.
      */
     struct keymgmt_data_st *keymgmt_data = vkeymgmt_data;
-    EVP_KEYMGMT *keymgmt = EVP_KEYMGMT_fetch(keymgmt_data->ctx, name,
-                                             keymgmt_data->properties);
+    EVP_KEYMGMT *keymgmt =
+        evp_keymgmt_fetch_by_number(keymgmt_data->ctx, name_id,
+                                    keymgmt_data->properties);
     EVP_SIGNATURE *signature = NULL;
     int ctxfncnt = 0, signfncnt = 0, verifyfncnt = 0, verifyrecfncnt = 0;
     int gparamfncnt = 0, sparamfncnt = 0;
@@ -58,12 +59,12 @@ static void *evp_signature_from_dispatch(const char *name,
         goto err;
     }
 
-    if ((signature = evp_signature_new(prov)) == NULL
-        || (signature->name = OPENSSL_strdup(name)) == NULL) {
+    if ((signature = evp_signature_new(prov)) == NULL) {
         ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
         goto err;
     }
 
+    signature->name_id = name_id;
     signature->keymgmt = keymgmt;
     keymgmt = NULL;              /* avoid double free on failure below */
 
@@ -189,7 +190,6 @@ void EVP_SIGNATURE_free(EVP_SIGNATURE *signature)
             return;
         EVP_KEYMGMT_free(signature->keymgmt);
         ossl_provider_free(signature->prov);
-        OPENSSL_free(signature->name);
         CRYPTO_THREAD_lock_free(signature->lock);
         OPENSSL_free(signature);
     }
diff --git a/crypto/include/internal/evp_int.h b/crypto/include/internal/evp_int.h
index caf0ca1dd9..f1fb67207f 100644
--- a/crypto/include/internal/evp_int.h
+++ b/crypto/include/internal/evp_int.h
@@ -130,7 +130,7 @@ extern const EVP_PKEY_METHOD siphash_pkey_meth;
 
 struct evp_mac_st {
     OSSL_PROVIDER *prov;
-    char *name;
+    int name_id;
 
     CRYPTO_REF_COUNT refcnt;
     CRYPTO_RWLOCK *lock;
@@ -152,7 +152,7 @@ struct evp_mac_st {
 
 struct evp_kdf_st {
     OSSL_PROVIDER *prov;
-    char *name;
+    int name_id;
     CRYPTO_REF_COUNT refcnt;
     CRYPTO_RWLOCK *lock;
 
@@ -199,7 +199,7 @@ struct evp_md_st {
 
     /* New structure members */
     /* TODO(3.0): Remove above comment when legacy has gone */
-    char *name;
+    int name_id;
     OSSL_PROVIDER *prov;
     CRYPTO_REF_COUNT refcnt;
     CRYPTO_RWLOCK *lock;
@@ -252,7 +252,7 @@ struct evp_cipher_st {
 
     /* New structure members */
     /* TODO(3.0): Remove above comment when legacy has gone */
-    char *name;
+    int name_id;
     OSSL_PROVIDER *prov;
     CRYPTO_REF_COUNT refcnt;
     CRYPTO_RWLOCK *lock;
diff --git a/doc/internal/man3/evp_generic_fetch.pod b/doc/internal/man3/evp_generic_fetch.pod
index b77391e386..6fe7bccba3 100644
--- a/doc/internal/man3/evp_generic_fetch.pod
+++ b/doc/internal/man3/evp_generic_fetch.pod
@@ -2,7 +2,8 @@
 
 =head1 NAME
 
-evp_generic_fetch - generic algorithm fetcher and method creator for EVP
+evp_generic_fetch, evp_generic_fetch_by_number
+- generic algorithm fetchers and method creators for EVP
 
 =head1 SYNOPSIS
 
@@ -11,7 +12,7 @@ evp_generic_fetch - generic algorithm fetcher and method creator for EVP
 
  void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
                          const char *name, const char *properties,
-                         void *(*new_method)(const char *name,
+                         void *(*new_method)(int name_id,
                                              const OSSL_DISPATCH *fns,
                                              OSSL_PROVIDER *prov,
                                              void *method_data),
@@ -19,23 +20,42 @@ evp_generic_fetch - generic algorithm fetcher and method creator for EVP
                          int (*up_ref_method)(void *),
                          void (*free_method)(void *));
 
+ void *evp_generic_fetch_by_number(OPENSSL_CTX *ctx, int operation_id,
+                                   int name_id, const char *properties,
+                                   void *(*new_method)(int name_id,
+                                                       const OSSL_DISPATCH *fns,
+                                                       OSSL_PROVIDER *prov,
+                                                       void *method_data),
+                                   void *method_data,
+                                   int (*up_ref_method)(void *),
+                                   void (*free_method)(void *));
+
 =head1 DESCRIPTION
 
 evp_generic_fetch() calls ossl_method_construct() with the given
-C<libctx>, C<operation_id>, C<name>, and C<properties> and uses
+I<libctx>, I<operation_id>, I<name>, and I<properties> and uses
 it to create an EVP method with the help of the functions
-C<new_method>, C<up_ref_method>, and C<free_method>.
+I<new_method>, I<up_ref_method>, and I<free_method>.
+
+evp_generic_fetch_by_number() does the same thing as evp_generic_fetch(), 
+but takes a I<name_id> instead of a number.
+I<name_id> must always be non-zero; as a matter of fact, it being zero
+is considered a programming error.
+This is meant to be used when one method needs to fetch an associated
+other method, and is typically called from inside the given function
+I<new_method>.
 
-The three functions are supposed to:
+The three functions I<new_method>, I<up_ref_method>, and
+I<free_method> are supposed to:
 
 =over 4
 
 =item new_method()
 
 creates an internal method from function pointers found in the
-dispatch table C<fns>.
-The algorithm I<name>, provider I<prov>, and I<method_data> are
-also passed to be used as new_method() sees fit.
+dispatch table I<fns>, with name identity I<name_id>.
+The provider I<prov> and I<method_data> are also passed to be used as
+new_method() sees fit.
 
 =item up_ref_method()
 
@@ -55,10 +75,10 @@ evp_generic_fetch() returns a method on success, or B<NULL> on error.
 =head1 EXAMPLES
 
 This is a short example of the fictitious EVP API and operation called
-C<EVP_FOO>.
+B<EVP_FOO>.
 
 To begin with, let's assume something like this in
-C<include/openssl/core_numbers.h>:
+F<include/openssl/core_numbers.h>:
 
     #define OSSL_OP_FOO                         100
 
@@ -80,6 +100,7 @@ And here's the implementation of the FOO method fetcher:
     /* typedef struct evp_foo_st EVP_FOO */
     struct evp_foo_st {
         OSSL_PROVIDER *prov;
+        int name_id;
 	CRYPTO_REF_COUNT refcnt;
         OSSL_OP_foo_newctx_fn *newctx;
         OSSL_OP_foo_init_fn *init;
@@ -92,14 +113,18 @@ And here's the implementation of the FOO method fetcher:
      * In this example, we have a public method creator and destructor.
      * It's not absolutely necessary, but is in the spirit of OpenSSL.
      */
-    EVP_FOO *EVP_FOO_meth_from_dispatch(const OSSL_DISPATCH *fns,
-                                        OSSL_PROVIDER *prov)
+    EVP_FOO *EVP_FOO_meth_from_dispatch(int name_id,
+                                        const OSSL_DISPATCH *fns,
+                                        OSSL_PROVIDER *prov,
+                                        void *data)
     {
         EVP_FOO *foo = NULL;
 
         if ((foo = OPENSSL_zalloc(sizeof(*foo))) == NULL)
             return NULL;
 
+        foo->name_id = name_id;
+
         for (; fns->function_id != 0; fns++) {
             switch (fns->function_id) {
             case OSSL_OP_FOO_NEWCTX_FUNC:
diff --git a/doc/internal/man3/ossl_method_construct.pod b/doc/internal/man3/ossl_method_construct.pod
index 9beb7942f0..a25ca4cd8c 100644
--- a/doc/internal/man3/ossl_method_construct.pod
+++ b/doc/internal/man3/ossl_method_construct.pod
@@ -15,13 +15,11 @@ OSSL_METHOD_CONSTRUCT_METHOD, ossl_method_construct
      /* Remove a store */
      void (*dealloc_tmp_store)(void *store);
      /* Get an already existing method from a store */
-     void *(*get)(OPENSSL_CTX *libctx, void *store,
-                  int operation_id, const char *name, const char *propquery,
-                  void *data);
+     void *(*get)(OPENSSL_CTX *libctx, void *store, void *data);
      /* Store a method in a store */
      int (*put)(OPENSSL_CTX *libctx, void *store, void *method,
-                int operation_id, const char *name, const char *propdef,
-                void *data);
+                const OSSL_PROVIDER *prov, int operation_id, const char *name,
+                const char *propdef, void *data);
      /* Construct a new method */
      void *(*construct)(const char *name, const OSSL_DISPATCH *fns,
                         OSSL_PROVIDER *prov, void *data);
@@ -31,7 +29,6 @@ OSSL_METHOD_CONSTRUCT_METHOD, ossl_method_construct
  typedef struct ossl_method_construct_method OSSL_METHOD_CONSTRUCT_METHOD;
 
  void *ossl_method_construct(OPENSSL_CTX *ctx, int operation_id,
-                             const char *name, const char *properties,
                              int force_cache,
                              OSSL_METHOD_CONSTRUCT_METHOD *mcm, void *mcm_data);
 
@@ -58,11 +55,10 @@ It's important to keep in mind that a method is identified by three things:
 =head2 Functions
 
 ossl_method_construct() creates a method by asking all available
-providers for a dispatch table given an I<operation_id>, an algorithm
-I<name> and a set of I<properties>, and then calling the appropriate
-functions given by the sub-system specific method creator through
-I<mcm> and the data in I<mcm_data> (which is passed by
-ossl_method_construct()).
+providers for a dispatch table given an I<operation_id>, and then
+calling the appropriate functions given by the sub-system specific
+method creator through I<mcm> and the data in I<mcm_data> (which is
+passed by ossl_method_construct()).
 
 This function assumes that the sub-system method creator implements
 reference counting and acts accordingly (i.e. it will call the
@@ -98,10 +94,10 @@ B<NULL> is a valid value and means that a sub-system default store
 must be used.
 This default store should be stored in the library context I<libctx>.
 
-The method to be looked up should be identified with the given
-I<operation_id>, I<name>, the provided property query I<propquery>
-and data from I<data> (which is the I<mcm_data> that was passed to
-ossl_construct_method()).
+The method to be looked up should be identified with data found in I<data>
+(which is the I<mcm_data> that was passed to ossl_construct_method()).
+In other words, the ossl_method_construct() caller is entirely responsible
+for ensuring the necesssary data is made available.
 
 This function is expected to increment the method's reference count.
 
diff --git a/doc/man3/EVP_EncryptInit.pod b/doc/man3/EVP_EncryptInit.pod
index 78f67bd643..a2ccc6f3d6 100644
--- a/doc/man3/EVP_EncryptInit.pod
+++ b/doc/man3/EVP_EncryptInit.pod
@@ -28,6 +28,7 @@ EVP_CipherFinal,
 EVP_get_cipherbyname,
 EVP_get_cipherbynid,
 EVP_get_cipherbyobj,
+EVP_CIPHER_is_a,
 EVP_CIPHER_name,
 EVP_CIPHER_provider,
 EVP_CIPHER_nid,
@@ -116,6 +117,7 @@ EVP_CIPHER_do_all_ex
  const EVP_CIPHER *EVP_get_cipherbyobj(const ASN1_OBJECT *a);
 
  int EVP_CIPHER_nid(const EVP_CIPHER *e);
+ int EVP_CIPHER_is_a(const EVP_CIPHER *cipher, const char *name);
  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);
@@ -315,6 +317,9 @@ 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_is_a() returns 1 if the given I<cipher> is an implementation of an
+algorithm that's identifiable with I<name>, otherwise 0.
+
 EVP_CIPHER_name() and EVP_CIPHER_CTX_name() return the name of the passed
 cipher or context.
 
diff --git a/doc/man3/EVP_MAC.pod b/doc/man3/EVP_MAC.pod
index 2ab4c48fbf..df15a907ec 100644
--- a/doc/man3/EVP_MAC.pod
+++ b/doc/man3/EVP_MAC.pod
@@ -2,7 +2,8 @@
 
 =head1 NAME
 
-EVP_MAC, EVP_MAC_fetch, EVP_MAC_up_ref, EVP_MAC_free, EVP_MAC_name,
+EVP_MAC, EVP_MAC_fetch, EVP_MAC_up_ref, EVP_MAC_free,
+EVP_MAC_is_a, EVP_MAC_name,
 EVP_MAC_provider, EVP_MAC_get_params, EVP_MAC_gettable_params,
 EVP_MAC_CTX, EVP_MAC_CTX_new, EVP_MAC_CTX_free, EVP_MAC_CTX_dup,
 EVP_MAC_CTX_mac, EVP_MAC_CTX_get_params, EVP_MAC_CTX_set_params,
@@ -21,6 +22,7 @@ EVP_MAC_do_all_ex - EVP MAC routines
                         const char *properties);
  int EVP_MAC_up_ref(EVP_MAC *mac);
  void EVP_MAC_free(EVP_MAC *mac);
+ int EVP_MAC_is_a(const EVP_MAC *mac, const char *name);
  const char *EVP_MAC_name(const EVP_MAC *mac);
  const OSSL_PROVIDER *EVP_MAC_provider(const EVP_MAC *mac);
  int EVP_MAC_get_params(EVP_MAC *mac, OSSL_PARAM params[]);
@@ -157,6 +159,9 @@ EVP_MAC_size() returns the MAC output size for the given context.
 
 EVP_MAC_name() returns the name of the given MAC implementation.
 
+EVP_MAC_is_a() checks if the given I<mac> is an implementation of an
+algorithm that's identifiable with I<name>.
+
 EVP_MAC_provider() returns the provider that holds the implementation
 of the given I<mac>.
 
@@ -256,6 +261,9 @@ EVP_MAC_free() returns nothing at all.
 EVP_MAC_name() returns the name of the MAC, or NULL if NULL was
 passed.
 
+EVP_MAC_is_a() returns 1 if the given method can be identified with
+the given name, otherwise 0.
+
 EVP_MAC_provider() returns a pointer to the provider for the MAC, or
 NULL on error.
 
diff --git a/include/internal/core.h b/include/internal/core.h
index a40d3c69af..d2229e173b 100644
--- a/include/internal/core.h
+++ b/include/internal/core.h
@@ -32,9 +32,7 @@ typedef struct ossl_method_construct_method_st {
     /* Remove a store */
     void (*dealloc_tmp_store)(void *store);
     /* Get an already existing method from a store */
-    void *(*get)(OPENSSL_CTX *libctx, void *store,
-                 int operation_id, const char *name, const char *propquery,
-                 void *data);
+    void *(*get)(OPENSSL_CTX *libctx, void *store, void *data);
     /* Store a method in a store */
     int (*put)(OPENSSL_CTX *libctx, void *store, void *method,
                const OSSL_PROVIDER *prov, int operation_id, const char *name,
@@ -47,7 +45,6 @@ typedef struct ossl_method_construct_method_st {
 } OSSL_METHOD_CONSTRUCT_METHOD;
 
 void *ossl_method_construct(OPENSSL_CTX *ctx, int operation_id,
-                            const char *name, const char *properties,
                             int force_cache,
                             OSSL_METHOD_CONSTRUCT_METHOD *mcm, void *mcm_data);
 
diff --git a/include/internal/namemap.h b/include/internal/namemap.h
index 57423801d6..ee69388f11 100644
--- a/include/internal/namemap.h
+++ b/include/internal/namemap.h
@@ -24,6 +24,8 @@ int ossl_namemap_add(OSSL_NAMEMAP *namemap, int number, const char *name);
  * number->name mapping is an iterator.
  */
 int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name);
+const char *ossl_namemap_num2name(const OSSL_NAMEMAP *namemap, int number,
+                                  size_t idx);
 void ossl_namemap_doall_names(const OSSL_NAMEMAP *namemap, int number,
                               void (*fn)(const char *name, void *data),
                               void *data);
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 2eb6802d3e..bbdc2b75c1 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -475,6 +475,7 @@ void *EVP_MD_CTX_md_data(const EVP_MD_CTX *ctx);
 
 int EVP_CIPHER_nid(const EVP_CIPHER *cipher);
 const char *EVP_CIPHER_name(const EVP_CIPHER *cipher);
+int EVP_CIPHER_is_a(const EVP_CIPHER *cipher, const char *name);
 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);
@@ -1034,6 +1035,7 @@ EVP_MAC *EVP_MAC_fetch(OPENSSL_CTX *libctx, const char *algorithm,
 int EVP_MAC_up_ref(EVP_MAC *mac);
 void EVP_MAC_free(EVP_MAC *mac);
 const char *EVP_MAC_name(const EVP_MAC *mac);
+int EVP_MAC_is_a(const EVP_MAC *mac, const char *name);
 const OSSL_PROVIDER *EVP_MAC_provider(const EVP_MAC *mac);
 int EVP_MAC_get_params(EVP_MAC *mac, OSSL_PARAM params[]);
 
diff --git a/providers/common/include/internal/provider_util.h b/providers/common/include/internal/provider_util.h
index c25c65886e..9fe21c5ef6 100644
--- a/providers/common/include/internal/provider_util.h
+++ b/providers/common/include/internal/provider_util.h
@@ -21,6 +21,9 @@ typedef struct {
 
     /* Conditions for legacy EVP_CIPHER uses */
     ENGINE *engine;             /* cipher engine */
+
+    /* Name this was fetched by */
+    char name[51];               /* A longer name would be unexpected */
 } PROV_CIPHER;
 
 typedef struct {
@@ -34,6 +37,9 @@ typedef struct {
 
     /* Conditions for legacy EVP_MD uses */
     ENGINE *engine;             /* digest engine */
+
+    /* Name this was fetched by */
+    char name[51];               /* A longer name would be unexpected */
 } PROV_DIGEST;
 
 /* Cipher functions */
@@ -43,19 +49,20 @@ typedef struct {
  * implementation used.  If a provider cannot be found, it falls back to trying
  * non-provider based implementations.
  */
-int ossl_prov_cipher_load_from_params(PROV_CIPHER *pd,
+int ossl_prov_cipher_load_from_params(PROV_CIPHER *pc,
                                       const OSSL_PARAM params[],
                                       OPENSSL_CTX *ctx);
 
 /* Reset the PROV_CIPHER fields and free any allocated cipher reference */
-void ossl_prov_cipher_reset(PROV_CIPHER *pd);
+void ossl_prov_cipher_reset(PROV_CIPHER *pc);
 
 /* Clone a PROV_CIPHER structure into a second */
 int ossl_prov_cipher_copy(PROV_CIPHER *dst, const PROV_CIPHER *src);
 
 /* Query the cipher and associated engine (if any) */
-const EVP_CIPHER *ossl_prov_cipher_cipher(const PROV_CIPHER *pd);
-ENGINE *ossl_prov_cipher_engine(const PROV_CIPHER *pd);
+const EVP_CIPHER *ossl_prov_cipher_cipher(const PROV_CIPHER *pc);
+ENGINE *ossl_prov_cipher_engine(const PROV_CIPHER *pc);
+const char *ossl_prov_cipher_name(const PROV_CIPHER *pc);
 
 /* Digest functions */
 /*
@@ -77,3 +84,4 @@ int ossl_prov_digest_copy(PROV_DIGEST *dst, const PROV_DIGEST *src);
 /* Query the digest and associated engine (if any) */
 const EVP_MD *ossl_prov_digest_md(const PROV_DIGEST *pd);
 ENGINE *ossl_prov_digest_engine(const PROV_DIGEST *pd);
+const char *ossl_prov_digest_name(const PROV_DIGEST *pd);
diff --git a/providers/common/kdfs/sskdf.c b/providers/common/kdfs/sskdf.c
index e7921bac35..49da1a690f 100644
--- a/providers/common/kdfs/sskdf.c
+++ b/providers/common/kdfs/sskdf.c
@@ -370,7 +370,6 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen)
         int ret;
         const unsigned char *custom = NULL;
         size_t custom_len = 0;
-        const char *macname;
         int default_salt_len;
 
         /*
@@ -378,8 +377,7 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen)
          * Why does KMAC require a salt length that's shorter than the MD
          * block size?
          */
-        macname = EVP_MAC_name(ctx->mac);
-        if (strcmp(macname, OSSL_MAC_NAME_HMAC) == 0) {
+        if (EVP_MAC_is_a(ctx->mac, OSSL_MAC_NAME_HMAC)) {
             /* H(x) = HMAC(x, salt, hash) */
             if (md == NULL) {
                 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST);
@@ -388,12 +386,12 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen)
             default_salt_len = EVP_MD_block_size(md);
             if (default_salt_len <= 0)
                 return 0;
-        } else if (strcmp(macname, OSSL_MAC_NAME_KMAC128) == 0
-                   || strcmp(macname, OSSL_MAC_NAME_KMAC256) == 0) {
+        } else if (EVP_MAC_is_a(ctx->mac, OSSL_MAC_NAME_KMAC128)
+                   || EVP_MAC_is_a(ctx->mac, OSSL_MAC_NAME_KMAC256)) {
             /* H(x) = KMACzzz(x, salt, custom) */
             custom = kmac_custom_str;
             custom_len = sizeof(kmac_custom_str);
-            if (strcmp(macname, OSSL_MAC_NAME_KMAC128) == 0)
+            if (EVP_MAC_is_a(ctx->mac, OSSL_MAC_NAME_KMAC128))
                 default_salt_len = SSKDF_KMAC128_DEFAULT_SALT_SIZE;
             else
                 default_salt_len = SSKDF_KMAC256_DEFAULT_SALT_SIZE;
diff --git a/providers/common/provider_util.c b/providers/common/provider_util.c
index 92cfb749c0..199544730a 100644
--- a/providers/common/provider_util.c
+++ b/providers/common/provider_util.c
@@ -17,6 +17,7 @@ void ossl_prov_cipher_reset(PROV_CIPHER *pc)
     pc->alloc_cipher = NULL;
     pc->cipher = NULL;
     pc->engine = NULL;
+    pc->name[0] = '\0';
 }
 
 int ossl_prov_cipher_copy(PROV_CIPHER *dst, const PROV_CIPHER *src)
@@ -26,6 +27,7 @@ int ossl_prov_cipher_copy(PROV_CIPHER *dst, const PROV_CIPHER *src)
     dst->engine = src->engine;
     dst->cipher = src->cipher;
     dst->alloc_cipher = src->alloc_cipher;
+    OPENSSL_strlcpy(dst->name, src->name, sizeof(dst->name));
     return 1;
 }
 
@@ -77,6 +79,7 @@ int ossl_prov_cipher_load_from_params(PROV_CIPHER *pc,
 
     EVP_CIPHER_free(pc->alloc_cipher);
     pc->cipher = pc->alloc_cipher = EVP_CIPHER_fetch(ctx, p->data, propquery);
+    OPENSSL_strlcpy(pc->name, p->data, sizeof(pc->name));
     /* TODO legacy stuff, to be removed */
 #ifndef FIPS_MODE /* Inside the FIPS module, we don't support legacy ciphers */
     if (pc->cipher == NULL)
@@ -95,12 +98,18 @@ ENGINE *ossl_prov_cipher_engine(const PROV_CIPHER *pc)
     return pc->engine;
 }
 
+const char *ossl_prov_cipher_name(const PROV_CIPHER *pc)
+{
+    return pc->name;
+}
+
 void ossl_prov_digest_reset(PROV_DIGEST *pd)
 {
     EVP_MD_free(pd->alloc_md);
     pd->alloc_md = NULL;
     pd->md = NULL;
     pd->engine = NULL;
+    pd->name[0] = '\0';
 }
 
 int ossl_prov_digest_copy(PROV_DIGEST *dst, const PROV_DIGEST *src)
@@ -110,6 +119,7 @@ int ossl_prov_digest_copy(PROV_DIGEST *dst, const PROV_DIGEST *src)
     dst->engine = src->engine;
     dst->md = src->md;
     dst->alloc_md = src->alloc_md;
+    OPENSSL_strlcpy(dst->name, src->name, sizeof(dst->name));
     return 1;
 }
 
@@ -132,6 +142,7 @@ int ossl_prov_digest_load_from_params(PROV_DIGEST *pd,
 
     EVP_MD_free(pd->alloc_md);
     pd->md = pd->alloc_md = EVP_MD_fetch(ctx, p->data, propquery);
+    OPENSSL_strlcpy(pd->name, p->data, sizeof(pd->name));
     /* TODO legacy stuff, to be removed */
 #ifndef FIPS_MODE /* Inside the FIPS module, we don't support legacy digests */
     if (pd->md == NULL)
@@ -150,3 +161,7 @@ ENGINE *ossl_prov_digest_engine(const PROV_DIGEST *pd)
     return pd->engine;
 }
 
+const char *ossl_prov_digest_name(const PROV_DIGEST *pd)
+{
+    return pd->name;
+}
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 71e650e933..1b14b440dc 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4762,3 +4762,5 @@ ERR_peek_error_all                      4878	3_0_0	EXIST::FUNCTION:
 ERR_peek_last_error_func                4879	3_0_0	EXIST::FUNCTION:
 ERR_peek_last_error_data                4880	3_0_0	EXIST::FUNCTION:
 ERR_peek_last_error_all                 4881	3_0_0	EXIST::FUNCTION:
+EVP_CIPHER_is_a                         4882	3_0_0	EXIST::FUNCTION:
+EVP_MAC_is_a                            4883	3_0_0	EXIST::FUNCTION:


More information about the openssl-commits mailing list