Replumbing: add support for multiple names per algorithm

Algorithms may have multiple names, as seen in the legacy names
database.  We need to support that as well.

This implementations modifies ossl_namemap to support multiple names
for the same identifier.

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/8967)
This commit is contained in:
Richard Levitte 2019-05-23 03:18:04 +02:00
parent 2c840201e5
commit 651d44183e
4 changed files with 143 additions and 114 deletions

View 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,69 +110,71 @@ 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.
*/
const char *ossl_namemap_name(const OSSL_NAMEMAP *namemap, int number)
{
NAMEMAP_ENTRY *entry;
#ifndef FIPS_MODE
if (namemap == NULL)
namemap = ossl_namemap_stored(NULL);
#endif
if (namemap == NULL || number == 0)
return NULL;
CRYPTO_THREAD_read_lock(namemap->lock);
entry = sk_NAMEMAP_ENTRY_value(namemap->numname, number);
CRYPTO_THREAD_unlock(namemap->lock);
if (entry != NULL)
return entry->name;
return NULL;
}
int ossl_namemap_number(const OSSL_NAMEMAP *namemap, const char *name)
{
NAMEMAP_ENTRY *entry, template;
#ifndef FIPS_MODE
if (namemap == NULL)
namemap = ossl_namemap_stored(NULL);
#endif
if (namemap == NULL)
return 0;
template.name = name;
CRYPTO_THREAD_read_lock(namemap->lock);
entry = lh_NAMEMAP_ENTRY_retrieve(namemap->namenum, &template);
CRYPTO_THREAD_unlock(namemap->lock);
if (entry == NULL)
return 0;
return entry->number;
}
int ossl_namemap_add(OSSL_NAMEMAP *namemap, const char *name)
{
NAMEMAP_ENTRY *entry;
typedef struct doall_names_data_st {
int number;
void (*fn)(const char *name, void *data);
void *data;
} DOALL_NAMES_DATA;
static void do_name(const NAMENUM_ENTRY *namenum, DOALL_NAMES_DATA *data)
{
if (namenum->number == data->number)
data->fn(namenum->name, data->data);
}
IMPLEMENT_LHASH_DOALL_ARG_CONST(NAMENUM_ENTRY, DOALL_NAMES_DATA);
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);
lh_NAMENUM_ENTRY_doall_DOALL_NAMES_DATA(namemap->namenum, do_name,
&cbdata);
CRYPTO_THREAD_unlock(namemap->lock);
}
int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name)
{
NAMENUM_ENTRY *namenum_entry, namenum_tmpl;
int number = 0;
#ifndef FIPS_MODE
if (namemap == NULL)
namemap = ossl_namemap_stored(NULL);
#endif
if (namemap == NULL)
return 0;
namenum_tmpl.name = (char *)name;
namenum_tmpl.number = 0;
CRYPTO_THREAD_read_lock(namemap->lock);
namenum_entry =
lh_NAMENUM_ENTRY_retrieve(namemap->namenum, &namenum_tmpl);
if (namenum_entry != NULL)
number = namenum_entry->number;
CRYPTO_THREAD_unlock(namemap->lock);
return number;
}
int ossl_namemap_add(OSSL_NAMEMAP *namemap, int number, const char *name)
{
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;
}

View file

@ -99,7 +99,7 @@ static void *get_method_from_store(OPENSSL_CTX *libctx, void *store,
return NULL;
if ((namemap = ossl_namemap_stored(libctx)) == NULL
|| (nameid = ossl_namemap_add(namemap, name)) == 0
|| (nameid = ossl_namemap_name2num(namemap, name)) == 0
|| (methid = method_id(operation_id, nameid)) == 0)
return NULL;
@ -123,7 +123,7 @@ static int put_method_in_store(OPENSSL_CTX *libctx, void *store,
uint32_t methid;
if ((namemap = ossl_namemap_stored(methdata->libctx)) == NULL
|| (nameid = ossl_namemap_add(namemap, name)) == 0
|| (nameid = ossl_namemap_add(namemap, 0, name)) == 0
|| (methid = method_id(operation_id, nameid)) == 0)
return 0;
@ -181,7 +181,7 @@ void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
* 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_number(namemap, name)) != 0
if ((nameid = ossl_namemap_name2num(namemap, name)) != 0
&& (methid = method_id(operation_id, nameid)) == 0)
return NULL;
@ -214,7 +214,7 @@ void *evp_generic_fetch(OPENSSL_CTX *libctx, int operation_id,
* already been calculated in get_method_from_store() and
* put_method_in_store() above.
*/
nameid = ossl_namemap_number(namemap, name);
nameid = ossl_namemap_name2num(namemap, name);
methid = method_id(operation_id, nameid);
ossl_method_store_cache_set(store, methid, properties, method);
}

View file

@ -3,7 +3,7 @@
=head1 NAME
ossl_namemap_new, ossl_namemap_free, ossl_namemap_stored,
ossl_namemap_add, ossl_namemap_name, ossl_namemap_number
ossl_namemap_add, ossl_namemap_name2num, ossl_namemap_doall_names
- internal number E<lt>-E<gt> name map
=head1 SYNOPSIS
@ -15,15 +15,18 @@ ossl_namemap_add, ossl_namemap_name, ossl_namemap_number
OSSL_NAMEMAP *ossl_namemap_new(void);
void ossl_namemap_free(OSSL_NAMEMAP *namemap);
int ossl_namemap_add(OSSL_NAMEMAP *namemap, const char *name);
const char *ossl_namemap_name(const OSSL_NAMEMAP *namemap, int number);
int ossl_namemap_number(const OSSL_NAMEMAP *namemap, const char *name);
int ossl_namemap_add(OSSL_NAMEMAP *namemap, int number, const char *name);
int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name);
void ossl_namemap_doall_names(const OSSL_NAMEMAP *namemap, int number,
void (*fn)(const char *name, void *data),
void *data);
=head1 DESCRIPTION
A B<OSSL_NAMEMAP> is a simple number E<lt>-E<gt> name map, which can
be used to give any arbitrary name (any string) a unique dynamic
identity that is valid throughout the lifetime of the associated
A B<OSSL_NAMEMAP> is a one-to-many number E<lt>-E<gt> names map, which
can be used to give any arbitrary set of names (any string) a unique
dynamic identity that is valid throughout the lifetime of the associated
library context.
ossl_namemap_new() and ossl_namemap_free() construct and destruct a
@ -38,11 +41,19 @@ ossl_namemap_free().
ossl_namemap_add() adds a new name to the namemap if it's not already
present.
If the given I<number> is zero, a new number will be allocated to
identify this I<name>.
If the given I<number> is non-zero, the I<name> is added to the set of
names already associated with that number.
ossl_namemap_name() finds the name corresponding to the given number.
ossl_namemap_name2num() finds the number corresponding to the given
I<name>.
ossl_namemap_number() finds the number corresponding to the given
name.
ossl_namemap_doall_names() walks through all names associated with
I<number> in the given I<namemap> and calls the function I<fn> for
each of them.
I<fn> is also passed the I<data> argument, which allows any caller to
pass extra data for that function to use.
=head1 RETURN VALUES
@ -52,12 +63,21 @@ B<OSSL_NAMEMAP>, or NULL on error.
ossl_namemap_add() returns the number associated with the added
string, or zero on error.
ossl_namemap_name() returns a pointer to the name corresponding to the
given number, or NULL if it's undefined in the given B<OSSL_NAMEMAP>.
ossl_namemap_num2names() returns a pointer to a NULL-terminated list of
pointers to the names corresponding to the given number, or NULL if
it's undefined in the given B<OSSL_NAMEMAP>.
ossl_namemap_number() returns the number corresponding to the given
ossl_namemap_name2num() returns the number corresponding to the given
name, or 0 if it's undefined in the given B<OSSL_NAMEMAP>.
=head1 NOTES
The result from ossl_namemap_num2names() isn't thread safe, other threads
dealing with the same namemap may cause the list of names to change
location.
It is therefore strongly recommended to only use the result in code
guarded by a thread lock.
=head1 HISTORY
The functions described here were all added in OpenSSL 3.0.

View file

@ -16,6 +16,14 @@ OSSL_NAMEMAP *ossl_namemap_stored(OPENSSL_CTX *libctx);
OSSL_NAMEMAP *ossl_namemap_new(void);
void ossl_namemap_free(OSSL_NAMEMAP *namemap);
int ossl_namemap_add(OSSL_NAMEMAP *namemap, const char *name);
const char *ossl_namemap_name(const OSSL_NAMEMAP *namemap, int number);
int ossl_namemap_number(const OSSL_NAMEMAP *namemap, const char *name);
int ossl_namemap_add(OSSL_NAMEMAP *namemap, int number, const char *name);
/*
* The number<->name relationship is 1<->many
* Therefore, the name->number mapping is a simple function, while the
* number->name mapping is an iterator.
*/
int ossl_namemap_name2num(const OSSL_NAMEMAP *namemap, const char *name);
void ossl_namemap_doall_names(const OSSL_NAMEMAP *namemap, int number,
void (*fn)(const char *name, void *data),
void *data);