X509_LOOKUP_store: Add CHANGES note
[openssl.git] / crypto / core_namemap.c
index 5155a2213492275f202e8bcbcd87f5b44732d7f6..71b70ff5aa0bcc14aa18a93582e7be7c478819b4 100644 (file)
@@ -7,45 +7,52 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include "e_os.h"                /* strcasecmp */
 #include "internal/namemap.h"
 #include <openssl/lhash.h>
-#include <openssl/safestack.h>
+#include "crypto/lhash.h"      /* openssl_lh_strcasehash */
 
-/* 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);
+    return openssl_lh_strcasehash(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);
+    return strcasecmp(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 +82,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 +99,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 +112,47 @@ 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_n(const OSSL_NAMEMAP *namemap,
+                            const char *name, size_t name_len)
 {
-    NAMEMAP_ENTRY *entry, template;
+    NAMENUM_ENTRY *namenum_entry, namenum_tmpl;
+    int number = 0;
 
 #ifndef FIPS_MODE
     if (namemap == NULL)
@@ -152,60 +162,99 @@ int ossl_namemap_number(const OSSL_NAMEMAP *namemap, const char *name)
     if (namemap == NULL)
         return 0;
 
-    template.name = name;
+    if ((namenum_tmpl.name = OPENSSL_strndup(name, name_len)) == NULL)
+        return 0;
+    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);
+    OPENSSL_free(namenum_tmpl.name);
 
-    if (entry == NULL)
+    return number;
+}
+
+int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name)
+{
+    if (name == NULL)
         return 0;
 
-    return entry->number;
+    return ossl_namemap_name2num_n(namemap, name, strlen(name));
+}
+
+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;
 }
 
-int ossl_namemap_add(OSSL_NAMEMAP *namemap, const char *name)
+const char *ossl_namemap_num2name(const OSSL_NAMEMAP *namemap, int number,
+                                  size_t idx)
 {
-    NAMEMAP_ENTRY *entry;
-    int number;
+    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_n(OSSL_NAMEMAP *namemap, int number,
+                       const char *name, size_t name_len)
+{
+    NAMENUM_ENTRY *namenum = NULL;
+    int tmp_number;
 
 #ifndef FIPS_MODE
     if (namemap == NULL)
         namemap = ossl_namemap_stored(NULL);
 #endif
 
-    if (name == NULL || namemap == NULL)
+    if (name == NULL || name_len == 0 || 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_n(namemap, name, name_len)) != 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_strndup(name, name_len)) == 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;
 }
+
+int ossl_namemap_add(OSSL_NAMEMAP *namemap, int number, const char *name)
+{
+    if (name == NULL)
+        return 0;
+
+    return ossl_namemap_add_n(namemap, number, name, strlen(name));
+}