Replumbing: add support for multiple names per algorithm
[openssl.git] / crypto / core_namemap.c
index 5155a22..31dc933 100644 (file)
@@ -9,43 +9,48 @@
 
 #include "internal/namemap.h"
 #include <openssl/lhash.h>
-#include <openssl/safestack.h>
 
-/* The namemap entry */
+/*-
+ * The namenum entry
+ * =================
+ */
 typedef struct {
+    char *name;
     int number;
-    const char *name;
-    char body[1];        /* Sized appropriately to contain the name */
-} NAMEMAP_ENTRY;
+} NAMENUM_ENTRY;
 
-DEFINE_LHASH_OF(NAMEMAP_ENTRY);
-DEFINE_STACK_OF(NAMEMAP_ENTRY)
+DEFINE_LHASH_OF(NAMENUM_ENTRY);
 
-/* The namemap, which provides for bidirectional indexing */
+/*-
+ * The namemap itself
+ * ==================
+ */
 
 struct ossl_namemap_st {
     /* Flags */
     unsigned int stored:1; /* If 1, it's stored in a library context */
 
     CRYPTO_RWLOCK *lock;
-    LHASH_OF(NAMEMAP_ENTRY) *namenum;  /* Name->number mapping */
-    STACK_OF(NAMEMAP_ENTRY) *numname;  /* Number->name mapping */
+    LHASH_OF(NAMENUM_ENTRY) *namenum;  /* Name->number mapping */
+    int max_number;                    /* Current max number */
 };
 
 /* LHASH callbacks */
 
-static unsigned long namemap_hash(const NAMEMAP_ENTRY *n)
+static unsigned long namenum_hash(const NAMENUM_ENTRY *n)
 {
     return OPENSSL_LH_strhash(n->name);
 }
 
-static int namemap_cmp(const NAMEMAP_ENTRY *a, const NAMEMAP_ENTRY *b)
+static int namenum_cmp(const NAMENUM_ENTRY *a, const NAMENUM_ENTRY *b)
 {
     return strcmp(a->name, b->name);
 }
 
-static void namemap_free(NAMEMAP_ENTRY *n)
+static void namenum_free(NAMENUM_ENTRY *n)
 {
+    if (n != NULL)
+        OPENSSL_free(n->name);
     OPENSSL_free(n);
 }
 
@@ -75,7 +80,10 @@ static const OPENSSL_CTX_METHOD stored_namemap_method = {
     stored_namemap_free,
 };
 
-/* API functions */
+/*-
+ * API functions
+ * =============
+ */
 
 OSSL_NAMEMAP *ossl_namemap_stored(OPENSSL_CTX *libctx)
 {
@@ -89,11 +97,9 @@ OSSL_NAMEMAP *ossl_namemap_new(void)
 
     if ((namemap = OPENSSL_zalloc(sizeof(*namemap))) != NULL
         && (namemap->lock = CRYPTO_THREAD_lock_new()) != NULL
-        && (namemap->numname = sk_NAMEMAP_ENTRY_new_null()) != NULL
         && (namemap->namenum =
-            lh_NAMEMAP_ENTRY_new(namemap_hash, namemap_cmp)) != NULL) {
+            lh_NAMENUM_ENTRY_new(namenum_hash, namenum_cmp)) != NULL)
         return namemap;
-    }
 
     ossl_namemap_free(namemap);
     return NULL;
@@ -104,45 +110,46 @@ void ossl_namemap_free(OSSL_NAMEMAP *namemap)
     if (namemap == NULL || namemap->stored)
         return;
 
-     /* The elements will be freed by sk_NAMEMAP_ENTRY_pop_free() */
-    lh_NAMEMAP_ENTRY_free(namemap->namenum);
-
-    sk_NAMEMAP_ENTRY_pop_free(namemap->numname, namemap_free);
+    lh_NAMENUM_ENTRY_doall(namemap->namenum, namenum_free);
+    lh_NAMENUM_ENTRY_free(namemap->namenum);
 
     CRYPTO_THREAD_lock_free(namemap->lock);
     OPENSSL_free(namemap);
 }
 
-/*
- * TODO(3.0) It isn't currently possible to have a default namemap in the
- * FIPS module because if init and cleanup constraints, so we currently
- * disable the code that would allow it when FIPS_MODE is defined.
- */
+typedef struct doall_names_data_st {
+    int number;
+    void (*fn)(const char *name, void *data);
+    void *data;
+} DOALL_NAMES_DATA;
 
-const char *ossl_namemap_name(const OSSL_NAMEMAP *namemap, int number)
+static void do_name(const NAMENUM_ENTRY *namenum, DOALL_NAMES_DATA *data)
 {
-    NAMEMAP_ENTRY *entry;
+    if (namenum->number == data->number)
+        data->fn(namenum->name, data->data);
+}
 
-#ifndef FIPS_MODE
-    if (namemap == NULL)
-        namemap = ossl_namemap_stored(NULL);
-#endif
+IMPLEMENT_LHASH_DOALL_ARG_CONST(NAMENUM_ENTRY, DOALL_NAMES_DATA);
 
-    if (namemap == NULL || number == 0)
-        return NULL;
+void ossl_namemap_doall_names(const OSSL_NAMEMAP *namemap, int number,
+                              void (*fn)(const char *name, void *data),
+                              void *data)
+{
+    DOALL_NAMES_DATA cbdata;
 
+    cbdata.number = number;
+    cbdata.fn = fn;
+    cbdata.data = data;
     CRYPTO_THREAD_read_lock(namemap->lock);
-    entry = sk_NAMEMAP_ENTRY_value(namemap->numname, number);
+    lh_NAMENUM_ENTRY_doall_DOALL_NAMES_DATA(namemap->namenum, do_name,
+                                            &cbdata);
     CRYPTO_THREAD_unlock(namemap->lock);
-
-    if (entry != NULL)
-        return entry->name;
-    return NULL;
 }
 
-int ossl_namemap_number(const OSSL_NAMEMAP *namemap, const char *name)
+int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name)
 {
-    NAMEMAP_ENTRY *entry, template;
+    NAMENUM_ENTRY *namenum_entry, namenum_tmpl;
+    int number = 0;
 
 #ifndef FIPS_MODE
     if (namemap == NULL)
@@ -152,21 +159,22 @@ int ossl_namemap_number(const OSSL_NAMEMAP *namemap, const char *name)
     if (namemap == NULL)
         return 0;
 
-    template.name = name;
+    namenum_tmpl.name = (char *)name;
+    namenum_tmpl.number = 0;
     CRYPTO_THREAD_read_lock(namemap->lock);
-    entry = lh_NAMEMAP_ENTRY_retrieve(namemap->namenum, &template);
+    namenum_entry =
+        lh_NAMENUM_ENTRY_retrieve(namemap->namenum, &namenum_tmpl);
+    if (namenum_entry != NULL)
+        number = namenum_entry->number;
     CRYPTO_THREAD_unlock(namemap->lock);
 
-    if (entry == NULL)
-        return 0;
-
-    return entry->number;
+    return number;
 }
 
-int ossl_namemap_add(OSSL_NAMEMAP *namemap, const char *name)
+int ossl_namemap_add(OSSL_NAMEMAP *namemap, int number, const char *name)
 {
-    NAMEMAP_ENTRY *entry;
-    int number;
+    NAMENUM_ENTRY *namenum = NULL;
+    int tmp_number;
 
 #ifndef FIPS_MODE
     if (namemap == NULL)
@@ -176,36 +184,29 @@ int ossl_namemap_add(OSSL_NAMEMAP *namemap, const char *name)
     if (name == NULL || namemap == NULL)
         return 0;
 
-    if ((number = ossl_namemap_number(namemap, name)) != 0)
-        return number;           /* Pretend success */
-
-    if ((entry = OPENSSL_zalloc(sizeof(*entry) + strlen(name))) == NULL)
-        goto err;
-
-    strcpy(entry->body, name);
-    entry->name = entry->body;
+    if ((tmp_number = ossl_namemap_name2num(namemap, name)) != 0)
+        return tmp_number;       /* Pretend success */
 
     CRYPTO_THREAD_write_lock(namemap->lock);
 
-    entry->number = sk_NAMEMAP_ENTRY_push(namemap->numname, entry);
-
-    if (entry->number == 0)
+    if ((namenum = OPENSSL_zalloc(sizeof(*namenum))) == NULL
+        || (namenum->name = OPENSSL_strdup(name)) == NULL)
         goto err;
 
-    (void)lh_NAMEMAP_ENTRY_insert(namemap->namenum, entry);
-    if (lh_NAMEMAP_ENTRY_error(namemap->namenum))
+    namenum->number = tmp_number =
+        number != 0 ? number : ++namemap->max_number;
+    (void)lh_NAMENUM_ENTRY_insert(namemap->namenum, namenum);
+
+    if (lh_NAMENUM_ENTRY_error(namemap->namenum))
         goto err;
 
     CRYPTO_THREAD_unlock(namemap->lock);
 
-    return entry->number;
+    return tmp_number;
 
  err:
-    if (entry != NULL) {
-        if (entry->number != 0)
-            (void)sk_NAMEMAP_ENTRY_pop(namemap->numname);
-        lh_NAMEMAP_ENTRY_delete(namemap->namenum, entry);
-        CRYPTO_THREAD_unlock(namemap->lock);
-    }
+    namenum_free(namenum);
+
+    CRYPTO_THREAD_unlock(namemap->lock);
     return 0;
 }