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 6e4414d..1e0d82f 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 d4c9419..cf5f1e5 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 0da934a..f39a443 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 f2511a2..6e509b2 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 662195e..79520c0 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 eeed735..000d6e9 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 fd684c4..cd58ba3 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 7c61a12..53a25a4 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 9f055a6..5c57cc3 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 c2db212..7bcdcc7 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 72ef1bd..c170bd6 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 a317127..3dc58c1 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 b46c92d..34db486 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 caf0ca1..f1fb672 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 b77391e..6fe7bcc 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 9beb794..a25ca4c 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 a40d3c6..d2229e1 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 5742380..ee69388 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);