In provider implemented methods, save the name number, not the name string
authorRichard Levitte <levitte@openssl.org>
Sat, 14 Sep 2019 14:22:19 +0000 (16:22 +0200)
committerRichard Levitte <levitte@openssl.org>
Thu, 19 Sep 2019 12:58:17 +0000 (14:58 +0200)
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@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9897)

18 files changed:
crypto/core_fetch.c
crypto/core_namemap.c
crypto/evp/digest.c
crypto/evp/evp_enc.c
crypto/evp/evp_fetch.c
crypto/evp/evp_lib.c
crypto/evp/evp_locl.h
crypto/evp/exchange.c
crypto/evp/kdf_lib.c
crypto/evp/kdf_meth.c
crypto/evp/keymgmt_meth.c
crypto/evp/mac_meth.c
crypto/evp/pmeth_fn.c
crypto/include/internal/evp_int.h
doc/internal/man3/evp_generic_fetch.pod
doc/internal/man3/ossl_method_construct.pod
include/internal/core.h
include/internal/namemap.h

index 6e4414d831bb1aeae1df2590b881971c48989e14..1e0d82fb6192d5d8cdb0a0dab851ff8b4d74d0fe 100644 (file)
@@ -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);
     }
 
index d4c9419044f220af7b0c43a81ceb0b4deb99f833..cf5f1e54c390879408a3f6b936448bfd6c3a3894 100644 (file)
@@ -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;
index 0da934a691007bd9eceacf2e4c5e3ba459ec01f1..f39a443c89ca4bc0d3555b3b7e6fdcc11dd05304 100644 (file)
@@ -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);
 }
index f2511a2b280fd428442cd9b3bd5685d83254ef5d..6e509b2d13ccbc9f4ccf334a3e5bb44b6a157818 100644 (file)
@@ -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);
 }
index 662195e4de08275c1d38f12b7800c2980e84e6e4..79520c0b7f9ccee550d9a900a08480ce60600569 100644 (file)
@@ -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,11 @@ 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);
+}
index eeed7359a41dd0a1dde6d88acb31ed7af988188a..000d6e9623a1fc8e97590a30d0e748d77dcb6de1 100644 (file)
@@ -451,7 +451,7 @@ int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx)
 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 +479,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
index fd684c4b4cfc950673b2de7183c95bdf9aab156c..cd58ba33b526f40d4fb649e91695783ae2d7fd41 100644 (file)
@@ -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,6 @@ 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);
index 7c61a12b3bae2fdbaa8c39d19910a57a81bc9eff..53a25a424e2fcf1ccc45547a82127a5070d7134e 100644 (file)
@@ -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);
     }
index 9f055a61d0df72f829d567acc1fbe7488d86868c..5c57cc360e908777ca3957d4de515263897c08b1 100644 (file)
@@ -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)
index c2db21271032d5ca57494e22da0f6e4c8f776f49..7bcdcc7df389d4bc852ada0b98b83ada30f5083f 100644 (file)
@@ -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) {
index 72ef1bdb0c222d61f2d144c3c33650b61ddfdc15..c170bd676b834cff973c13986630861f0a56fb89 100644 (file)
@@ -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);
 }
index a317127e157867e887bf494afc87af2d7a78aca4..3dc58c1f3be896f612020e8dbd8e9efcdbf2da0c 100644 (file)
@@ -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) {
@@ -170,7 +170,7 @@ void EVP_MAC_free(EVP_MAC *mac)
 
 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)
index b46c92d633fdffe1cbca888e7663c0705dbf62fc..34db48639aed482e8d8c958d975ef78f0dad0dd6 100644 (file)
@@ -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);
     }
index caf0ca1dd9e3151191af59724518f765716f55c1..f1fb67207fd0ef7979fff68a3fceca6b5c80498b 100644 (file)
@@ -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;
index b77391e38668a75fed868ac42f56b2dccb874978..6fe7bccba377c264b92a8f78f71f2e11598cb763 100644 (file)
@@ -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:
index 9beb7942f0ae7a2aa3f2fefaba08c0c288833bb2..a25ca4cd8c6893c1e22c4025666e6380dc7e342d 100644 (file)
@@ -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.
 
index a40d3c69aff1231990234f269f1d82adfaaac094..d2229e173b2c4f3f47fc87d02923a4b7e6034fa1 100644 (file)
@@ -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);
 
index 57423801d61eb7b283cba6c846feaabfae8178e1..ee69388f113fa50ec82a303ed5a93a6467a1c315 100644 (file)
@@ -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);