Create internal number<->name mapping API

This can be used as a general name to identity map.

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/8878)
This commit is contained in:
Richard Levitte 2019-05-04 12:55:32 +02:00
parent ffa9bff8a2
commit f2182a4e6f
5 changed files with 309 additions and 2 deletions

View File

@ -10,7 +10,7 @@ SUBDIRS=objects buffer bio stack lhash rand evp asn1 pem x509 x509v3 conf \
LIBS=../libcrypto
# The Core
SOURCE[../libcrypto]=provider_core.c provider_predefined.c provider_conf.c \
core_fetch.c
core_fetch.c core_namemap.c
# Central utilities
SOURCE[../libcrypto]=\

211
crypto/core_namemap.c Normal file
View File

@ -0,0 +1,211 @@
/*
* Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "internal/namemap.h"
#include <openssl/lhash.h>
#include <openssl/safestack.h>
/* The namemap entry */
typedef struct {
int number;
const char *name;
char body[1]; /* Sized appropriately to contain the name */
} NAMEMAP_ENTRY;
DEFINE_LHASH_OF(NAMEMAP_ENTRY);
DEFINE_STACK_OF(NAMEMAP_ENTRY)
/* The namemap, which provides for bidirectional indexing */
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 callbacks */
static unsigned long namemap_hash(const NAMEMAP_ENTRY *n)
{
return OPENSSL_LH_strhash(n->name);
}
static int namemap_cmp(const NAMEMAP_ENTRY *a, const NAMEMAP_ENTRY *b)
{
return strcmp(a->name, b->name);
}
static void namemap_free(NAMEMAP_ENTRY *n)
{
OPENSSL_free(n);
}
/* OPENSSL_CTX_METHOD functions for a namemap stored in a library context */
static void *stored_namemap_new(OPENSSL_CTX *libctx)
{
OSSL_NAMEMAP *namemap = ossl_namemap_new();
if (namemap != NULL)
namemap->stored = 1;
return namemap;
}
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);
}
static const OPENSSL_CTX_METHOD stored_namemap_method = {
stored_namemap_new,
stored_namemap_free,
};
/* API functions */
OSSL_NAMEMAP *ossl_namemap_stored(OPENSSL_CTX *libctx)
{
return openssl_ctx_get_data(libctx, OPENSSL_CTX_NAMEMAP_INDEX,
&stored_namemap_method);
}
OSSL_NAMEMAP *ossl_namemap_new(void)
{
OSSL_NAMEMAP *namemap;
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) {
return namemap;
}
ossl_namemap_free(namemap);
return NULL;
}
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);
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;
int number;
#ifndef FIPS_MODE
if (namemap == NULL)
namemap = ossl_namemap_stored(NULL);
#endif
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;
CRYPTO_THREAD_write_lock(namemap->lock);
entry->number = sk_NAMEMAP_ENTRY_push(namemap->numname, entry);
if (entry->number == 0)
goto err;
(void)lh_NAMEMAP_ENTRY_insert(namemap->namenum, entry);
if (lh_NAMEMAP_ENTRY_error(namemap->namenum))
goto err;
CRYPTO_THREAD_unlock(namemap->lock);
return entry->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);
}
return 0;
}

View File

@ -0,0 +1,74 @@
=pod
=head1 NAME
ossl_namemap_new, ossl_namemap_free, ossl_namemap_stored,
ossl_namemap_add, ossl_namemap_name, ossl_namemap_number
- internal number E<lt>-E<gt> name map
=head1 SYNOPSIS
#include "internal/cryptlib.h"
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);
=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
library context.
ossl_namemap_new() and ossl_namemap_free() construct and destruct a
new B<OSSL_NAMEMAP>.
This is suitable to use when the B<OSSL_NAMEMAP> is embedded in other
structures, or should be independent for any reason.
ossl_namemap_stored() finds or auto-creates the default namemap in the
given library context.
The returned B<OSSL_NAMEMAP> can't be destructed using
ossl_namemap_free().
ossl_namemap_add() adds a new name to the namemap if it's not already
present.
ossl_namemap_name() finds the name corresponding to the given number.
ossl_namemap_number() finds the number corresponding to the given
name.
=head1 RETURN VALUES
ossl_namemap_new() and ossl_namemap_stored() return the pointer to a
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_number() returns the number corresponding to the given
name, or 0 if it's undefined in the given B<OSSL_NAMEMAP>.
=head1 HISTORY
The functions described here were all added in OpenSSL 3.0.
=head1 COPYRIGHT
Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use
this file except in compliance with the License. You can obtain a copy
in the file LICENSE in the source distribution or at
L<https://www.openssl.org/source/license.html>.
=cut

View File

@ -145,7 +145,8 @@ typedef struct ossl_ex_data_global_st {
# define OPENSSL_CTX_PROVIDER_STORE_INDEX 1
# define OPENSSL_CTX_PROPERTY_DEFN_INDEX 2
# define OPENSSL_CTX_PROPERTY_STRING_INDEX 3
# define OPENSSL_CTX_MAX_INDEXES 4
# define OPENSSL_CTX_NAMEMAP_INDEX 4
# define OPENSSL_CTX_MAX_INDEXES 5
typedef struct openssl_ctx_method {
void *(*new_func)(OPENSSL_CTX *ctx);

View File

@ -0,0 +1,21 @@
/*
* Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include "internal/cryptlib.h"
typedef struct ossl_namemap_st OSSL_NAMEMAP;
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);