From 651d44183e86355b1eb9629a6a61d3da09369bbf Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Thu, 23 May 2019 03:18:04 +0200 Subject: [PATCH 1/1] 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 (Merged from https://github.com/openssl/openssl/pull/8967) --- crypto/core_namemap.c | 141 +++++++++++++------------ crypto/evp/evp_fetch.c | 8 +- doc/internal/man3/ossl_namemap_new.pod | 46 +++++--- include/internal/namemap.h | 14 ++- 4 files changed, 119 insertions(+), 90 deletions(-) diff --git a/crypto/core_namemap.c b/crypto/core_namemap.c index 5155a22134..31dc933af1 100644 --- a/crypto/core_namemap.c +++ b/crypto/core_namemap.c @@ -9,43 +9,48 @@ #include "internal/namemap.h" #include -#include -/* 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; } diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c index 1c9e27db87..b039cc0547 100644 --- a/crypto/evp/evp_fetch.c +++ b/crypto/evp/evp_fetch.c @@ -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); } diff --git a/doc/internal/man3/ossl_namemap_new.pod b/doc/internal/man3/ossl_namemap_new.pod index 07dc914fe2..8699b861b0 100644 --- a/doc/internal/man3/ossl_namemap_new.pod +++ b/doc/internal/man3/ossl_namemap_new.pod @@ -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-E 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 is a simple number E-E 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 is a one-to-many number E-E 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 is zero, a new number will be allocated to +identify this I. +If the given I is non-zero, the I 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. -ossl_namemap_number() finds the number corresponding to the given -name. +ossl_namemap_doall_names() walks through all names associated with +I in the given I and calls the function I for +each of them. +I is also passed the I argument, which allows any caller to +pass extra data for that function to use. =head1 RETURN VALUES @@ -52,12 +63,21 @@ B, 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_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_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. +=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. diff --git a/include/internal/namemap.h b/include/internal/namemap.h index 30028182fd..57423801d6 100644 --- a/include/internal/namemap.h +++ b/include/internal/namemap.h @@ -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); -- 2.34.1