CORE: ossl_namemap_add_names(): new function to add multiple names
[openssl.git] / crypto / core_namemap.c
index cb26b429b7519d2f775a99153610666e30e58ffe..39356076e5d9257f4ce3348c62c238f0c1e7a22a 100644 (file)
@@ -72,9 +72,11 @@ static void stored_namemap_free(void *vnamemap)
 {
     OSSL_NAMEMAP *namemap = vnamemap;
 
-    /* Pretend it isn't stored, or ossl_namemap_free() will do nothing */
-    namemap->stored = 0;
-    ossl_namemap_free(namemap);
+    if (namemap != NULL) {
+        /* Pretend it isn't stored, or ossl_namemap_free() will do nothing */
+        namemap->stored = 0;
+        ossl_namemap_free(namemap);
+    }
 }
 
 static const OPENSSL_CTX_METHOD stored_namemap_method = {
@@ -119,6 +121,18 @@ void ossl_namemap_free(OSSL_NAMEMAP *namemap)
     OPENSSL_free(namemap);
 }
 
+int ossl_namemap_empty(OSSL_NAMEMAP *namemap)
+{
+    int rv = 0;
+
+    CRYPTO_THREAD_read_lock(namemap->lock);
+    if (namemap->max_number == 0)
+        rv = 1;
+    CRYPTO_THREAD_unlock(namemap->lock);
+
+    return rv;
+}
+
 typedef struct doall_names_data_st {
     int number;
     void (*fn)(const char *name, void *data);
@@ -148,7 +162,8 @@ void ossl_namemap_doall_names(const OSSL_NAMEMAP *namemap, int number,
     CRYPTO_THREAD_unlock(namemap->lock);
 }
 
-int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name)
+int ossl_namemap_name2num_n(const OSSL_NAMEMAP *namemap,
+                            const char *name, size_t name_len)
 {
     NAMENUM_ENTRY *namenum_entry, namenum_tmpl;
     int number = 0;
@@ -161,7 +176,8 @@ int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name)
     if (namemap == NULL)
         return 0;
 
-    namenum_tmpl.name = (char *)name;
+    if ((namenum_tmpl.name = OPENSSL_strndup(name, name_len)) == NULL)
+        return 0;
     namenum_tmpl.number = 0;
     CRYPTO_THREAD_read_lock(namemap->lock);
     namenum_entry =
@@ -169,10 +185,19 @@ int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name)
     if (namenum_entry != NULL)
         number = namenum_entry->number;
     CRYPTO_THREAD_unlock(namemap->lock);
+    OPENSSL_free(namenum_tmpl.name);
 
     return number;
 }
 
+int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name)
+{
+    if (name == NULL)
+        return 0;
+
+    return ossl_namemap_name2num_n(namemap, name, strlen(name));
+}
+
 struct num2name_data_st {
     size_t idx;                  /* Countdown */
     const char *name;            /* Result */
@@ -199,7 +224,8 @@ const char *ossl_namemap_num2name(const OSSL_NAMEMAP *namemap, int number,
     return data.name;
 }
 
-int ossl_namemap_add(OSSL_NAMEMAP *namemap, int number, const char *name)
+int ossl_namemap_add_name_n(OSSL_NAMEMAP *namemap, int number,
+                            const char *name, size_t name_len)
 {
     NAMENUM_ENTRY *namenum = NULL;
     int tmp_number;
@@ -209,16 +235,16 @@ int ossl_namemap_add(OSSL_NAMEMAP *namemap, int number, const char *name)
         namemap = ossl_namemap_stored(NULL);
 #endif
 
-    if (name == NULL || namemap == NULL)
+    if (name == NULL || name_len == 0 || namemap == NULL)
         return 0;
 
-    if ((tmp_number = ossl_namemap_name2num(namemap, name)) != 0)
+    if ((tmp_number = ossl_namemap_name2num_n(namemap, name, name_len)) != 0)
         return tmp_number;       /* Pretend success */
 
     CRYPTO_THREAD_write_lock(namemap->lock);
 
     if ((namenum = OPENSSL_zalloc(sizeof(*namenum))) == NULL
-        || (namenum->name = OPENSSL_strdup(name)) == NULL)
+        || (namenum->name = OPENSSL_strndup(name, name_len)) == NULL)
         goto err;
 
     namenum->number = tmp_number =
@@ -238,3 +264,74 @@ int ossl_namemap_add(OSSL_NAMEMAP *namemap, int number, const char *name)
     CRYPTO_THREAD_unlock(namemap->lock);
     return 0;
 }
+
+int ossl_namemap_add_name(OSSL_NAMEMAP *namemap, int number, const char *name)
+{
+    if (name == NULL)
+        return 0;
+
+    return ossl_namemap_add_name_n(namemap, number, name, strlen(name));
+}
+
+int ossl_namemap_add_names(OSSL_NAMEMAP *namemap, int number,
+                           const char *names, const char separator)
+{
+    const char *p, *q;
+    size_t l;
+
+    /* Check that we have a namemap */
+    if (!ossl_assert(namemap != NULL)) {
+        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    /*
+     * Check that no name is an empty string, and that all names have at
+     * most one numeric identity together.
+     */
+    for (p = names; *p != '\0'; p = (q == NULL ? p + l : q + 1)) {
+        int this_number;
+
+        if ((q = strchr(p, separator)) == NULL)
+            l = strlen(p);       /* offset to \0 */
+        else
+            l = q - p;           /* offset to the next separator */
+
+        this_number = ossl_namemap_name2num_n(namemap, p, l);
+
+        if (*p == '\0' || *p == separator) {
+            ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_BAD_ALGORITHM_NAME);
+            return 0;
+        }
+        if (number == 0) {
+            number = this_number;
+        } else if (this_number != 0 && this_number != number) {
+            ERR_raise_data(ERR_LIB_CRYPTO, CRYPTO_R_CONFLICTING_NAMES,
+                           "\"%.*s\" has an existing different identity %d (from \"%s\")",
+                           l, p, this_number, names);
+            return 0;
+        }
+    }
+
+    /* Now that we have checked, register all names */
+    for (p = names; *p != '\0'; p = (q == NULL ? p + l : q + 1)) {
+        int this_number;
+
+        if ((q = strchr(p, separator)) == NULL)
+            l = strlen(p);       /* offset to \0 */
+        else
+            l = q - p;           /* offset to the next separator */
+
+        this_number = ossl_namemap_add_name_n(namemap, number, p, l);
+        if (number == 0) {
+            number = this_number;
+        } else if (this_number != number) {
+            ERR_raise_data(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR,
+                           "Got number %d when expecting %d",
+                           this_number, number);
+            return 0;
+        }
+    }
+
+    return number;
+}