2 * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 #include "internal/namemap.h"
11 #include <openssl/lhash.h>
12 #include <openssl/safestack.h>
14 /* The namemap entry */
18 char body[1]; /* Sized appropriately to contain the name */
21 DEFINE_LHASH_OF(NAMEMAP_ENTRY);
22 DEFINE_STACK_OF(NAMEMAP_ENTRY)
24 /* The namemap, which provides for bidirectional indexing */
26 struct ossl_namemap_st {
28 unsigned int stored:1; /* If 1, it's stored in a library context */
31 LHASH_OF(NAMEMAP_ENTRY) *namenum; /* Name->number mapping */
32 STACK_OF(NAMEMAP_ENTRY) *numname; /* Number->name mapping */
37 static unsigned long namemap_hash(const NAMEMAP_ENTRY *n)
39 return OPENSSL_LH_strhash(n->name);
42 static int namemap_cmp(const NAMEMAP_ENTRY *a, const NAMEMAP_ENTRY *b)
44 return strcmp(a->name, b->name);
47 static void namemap_free(NAMEMAP_ENTRY *n)
52 /* OPENSSL_CTX_METHOD functions for a namemap stored in a library context */
54 static void *stored_namemap_new(OPENSSL_CTX *libctx)
56 OSSL_NAMEMAP *namemap = ossl_namemap_new();
64 static void stored_namemap_free(void *vnamemap)
66 OSSL_NAMEMAP *namemap = vnamemap;
68 /* Pretend it isn't stored, or ossl_namemap_free() will do nothing */
70 ossl_namemap_free(namemap);
73 static const OPENSSL_CTX_METHOD stored_namemap_method = {
80 OSSL_NAMEMAP *ossl_namemap_stored(OPENSSL_CTX *libctx)
82 return openssl_ctx_get_data(libctx, OPENSSL_CTX_NAMEMAP_INDEX,
83 &stored_namemap_method);
86 OSSL_NAMEMAP *ossl_namemap_new(void)
88 OSSL_NAMEMAP *namemap;
90 if ((namemap = OPENSSL_zalloc(sizeof(*namemap))) != NULL
91 && (namemap->lock = CRYPTO_THREAD_lock_new()) != NULL
92 && (namemap->numname = sk_NAMEMAP_ENTRY_new_null()) != NULL
93 && (namemap->namenum =
94 lh_NAMEMAP_ENTRY_new(namemap_hash, namemap_cmp)) != NULL) {
98 ossl_namemap_free(namemap);
102 void ossl_namemap_free(OSSL_NAMEMAP *namemap)
104 if (namemap == NULL || namemap->stored)
107 /* The elements will be freed by sk_NAMEMAP_ENTRY_pop_free() */
108 lh_NAMEMAP_ENTRY_free(namemap->namenum);
110 sk_NAMEMAP_ENTRY_pop_free(namemap->numname, namemap_free);
112 CRYPTO_THREAD_lock_free(namemap->lock);
113 OPENSSL_free(namemap);
117 * TODO(3.0) It isn't currently possible to have a default namemap in the
118 * FIPS module because if init and cleanup constraints, so we currently
119 * disable the code that would allow it when FIPS_MODE is defined.
122 const char *ossl_namemap_name(const OSSL_NAMEMAP *namemap, int number)
124 NAMEMAP_ENTRY *entry;
128 namemap = ossl_namemap_stored(NULL);
131 if (namemap == NULL || number == 0)
134 CRYPTO_THREAD_read_lock(namemap->lock);
135 entry = sk_NAMEMAP_ENTRY_value(namemap->numname, number);
136 CRYPTO_THREAD_unlock(namemap->lock);
143 int ossl_namemap_number(const OSSL_NAMEMAP *namemap, const char *name)
145 NAMEMAP_ENTRY *entry, template;
149 namemap = ossl_namemap_stored(NULL);
155 template.name = name;
156 CRYPTO_THREAD_read_lock(namemap->lock);
157 entry = lh_NAMEMAP_ENTRY_retrieve(namemap->namenum, &template);
158 CRYPTO_THREAD_unlock(namemap->lock);
163 return entry->number;
166 int ossl_namemap_add(OSSL_NAMEMAP *namemap, const char *name)
168 NAMEMAP_ENTRY *entry;
173 namemap = ossl_namemap_stored(NULL);
176 if (name == NULL || namemap == NULL)
179 if ((number = ossl_namemap_number(namemap, name)) != 0)
180 return number; /* Pretend success */
182 if ((entry = OPENSSL_zalloc(sizeof(*entry) + strlen(name))) == NULL)
185 strcpy(entry->body, name);
186 entry->name = entry->body;
188 CRYPTO_THREAD_write_lock(namemap->lock);
190 entry->number = sk_NAMEMAP_ENTRY_push(namemap->numname, entry);
192 if (entry->number == 0)
195 (void)lh_NAMEMAP_ENTRY_insert(namemap->namenum, entry);
196 if (lh_NAMEMAP_ENTRY_error(namemap->namenum))
199 CRYPTO_THREAD_unlock(namemap->lock);
201 return entry->number;
205 if (entry->number != 0)
206 (void)sk_NAMEMAP_ENTRY_pop(namemap->numname);
207 lh_NAMEMAP_ENTRY_delete(namemap->namenum, entry);
208 CRYPTO_THREAD_unlock(namemap->lock);