Adding in curl and openssl repos

This commit is contained in:
2025-08-14 12:09:30 -04:00
parent af2117b574
commit 0ace93e303
21174 changed files with 3607720 additions and 2 deletions

View File

@@ -0,0 +1,94 @@
Selecting algorithm implementations by properties
=================================================
Properties are associated with algorithms and are used to select between
different implementations dynamically.
This implementation is based on a number of assumptions:
* Property definition is uncommon. I.e. providers will be loaded and
unloaded relatively infrequently, if at all.
* The number of distinct property names will be small.
* Providers will often give the same implementation properties to most or
all of their implemented algorithms. E.g. the FIPS property would be set
across an entire provider. Likewise for, hardware, accelerated, software,
HSM and, perhaps, constant_time.
* There are a lot of algorithm implementations, therefore property
definitions should be space efficient. However...
* ... property queries are very common. These must be fast.
* Property queries come from a small set and are reused many times typically.
I.e. an application tends to use the same set of queries over and over,
rather than spanning a wide variety of queries.
* Property queries can never add new property definitions.
Some consequences of these assumptions are:
* That definition is uncommon and queries are very common, we can treat
the property definitions as almost immutable. Specifically, a query can
never change the state of the definitions.
* That definition is uncommon and needs to be space efficient, it will
be feasible to use a hash table to contain the names (and possibly also
values) of all properties and to reference these instead of duplicating
strings. Moreover, such a data structure need not be garbage collected.
By converting strings to integers using a structure such as this, string
comparison degenerates to integer comparison. Additionally, lists of
properties can be sorted by the string index which makes comparisons linear
time rather than quadratic time - the O(n log n) sort cost being amortised.
* A cache for property definitions is also viable, if only implementation
properties are used and not algorithm properties, or at least these are
maintained separately. This cache would be a hash table, indexed by
the property definition string, and algorithms with the same properties
would share their definition structure. Again, reducing space use.
* A query cache is desirable. This would be a hash table keyed by the
algorithm identifier and the entire query string and it would map to
the chosen algorithm. When a provider is loaded or unloaded, this cache
must be invalidated. The cache will also be invalidated when the global
properties are changed as doing so removes the need to index on both the
global and requested property strings.
The implementation:
* [property_lock.c](property_lock.c)
contains some wrapper functions to handle the global
lock more easily. The global lock is held for short periods of time with
per algorithm locking being used for longer intervals.
* [property_string.c](property_string.c)
contains the string cache which converts property
names and values to small integer indices. Names and values are stored in
separate hash tables. The two Boolean values, the strings "yes" and "no",
are populated as the first two members of the value table. All property
names reserved by OpenSSL are also populated here. No functions are
provided to convert from an index back to the original string (this can be
done by maintaining parallel stacks of strings if required).
* [property_parse.c](property_parse.c)
contains the property definition and query parsers.
These convert ASCII strings into lists of properties. The resulting
lists are sorted by the name index. Some additional utility functions
for dealing with property lists are also included: comparison of a query
against a definition and merging two queries into a single larger query.
* [property.c](property.c)
contains the main APIs for defining and using properties.
Algorithms are discovered from their NID and a query string.
The results are cached.
The caching of query results has to be efficient but it must also be robust
against a denial of service attack. The cache cannot be permitted to grow
without bounds and must garbage collect under-used entries. The garbage
collection does not have to be exact.
* [defn_cache.c](defn_cache.c)
contains a cache that maps property definition strings to
parsed properties. It is used by property.c to improve performance when
the same definition appears multiple times.

View File

@@ -0,0 +1,4 @@
LIBS=../../libcrypto
$COMMON=property_string.c property_parse.c property_query.c property.c defn_cache.c
SOURCE[../../libcrypto]=$COMMON property_err.c
SOURCE[../../providers/libfips.a]=$COMMON

View File

@@ -0,0 +1,136 @@
/*
* Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2019, Oracle and/or its affiliates. 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 <string.h>
#include <openssl/err.h>
#include <openssl/lhash.h>
#include "internal/propertyerr.h"
#include "internal/property.h"
#include "internal/core.h"
#include "property_local.h"
#include "crypto/context.h"
/*
* Implement a property definition cache.
* These functions assume that they are called under a write lock.
* No attempt is made to clean out the cache, except when it is shut down.
*/
typedef struct {
const char *prop;
OSSL_PROPERTY_LIST *defn;
char body[1];
} PROPERTY_DEFN_ELEM;
DEFINE_LHASH_OF_EX(PROPERTY_DEFN_ELEM);
static unsigned long property_defn_hash(const PROPERTY_DEFN_ELEM *a)
{
return OPENSSL_LH_strhash(a->prop);
}
static int property_defn_cmp(const PROPERTY_DEFN_ELEM *a,
const PROPERTY_DEFN_ELEM *b)
{
return strcmp(a->prop, b->prop);
}
static void property_defn_free(PROPERTY_DEFN_ELEM *elem)
{
ossl_property_free(elem->defn);
OPENSSL_free(elem);
}
void ossl_property_defns_free(void *vproperty_defns)
{
LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns = vproperty_defns;
if (property_defns != NULL) {
lh_PROPERTY_DEFN_ELEM_doall(property_defns,
&property_defn_free);
lh_PROPERTY_DEFN_ELEM_free(property_defns);
}
}
void *ossl_property_defns_new(OSSL_LIB_CTX *ctx) {
return lh_PROPERTY_DEFN_ELEM_new(&property_defn_hash, &property_defn_cmp);
}
OSSL_PROPERTY_LIST *ossl_prop_defn_get(OSSL_LIB_CTX *ctx, const char *prop)
{
PROPERTY_DEFN_ELEM elem, *r;
LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns;
property_defns = ossl_lib_ctx_get_data(ctx,
OSSL_LIB_CTX_PROPERTY_DEFN_INDEX);
if (!ossl_assert(property_defns != NULL) || !ossl_lib_ctx_read_lock(ctx))
return NULL;
elem.prop = prop;
r = lh_PROPERTY_DEFN_ELEM_retrieve(property_defns, &elem);
ossl_lib_ctx_unlock(ctx);
if (r == NULL || !ossl_assert(r->defn != NULL))
return NULL;
return r->defn;
}
/*
* Cache the property list for a given property string *pl.
* If an entry already exists in the cache *pl is freed and
* overwritten with the existing entry from the cache.
*/
int ossl_prop_defn_set(OSSL_LIB_CTX *ctx, const char *prop,
OSSL_PROPERTY_LIST **pl)
{
PROPERTY_DEFN_ELEM elem, *old, *p = NULL;
size_t len;
LHASH_OF(PROPERTY_DEFN_ELEM) *property_defns;
int res = 1;
property_defns = ossl_lib_ctx_get_data(ctx,
OSSL_LIB_CTX_PROPERTY_DEFN_INDEX);
if (property_defns == NULL)
return 0;
if (prop == NULL)
return 1;
if (!ossl_lib_ctx_write_lock(ctx))
return 0;
elem.prop = prop;
if (pl == NULL) {
lh_PROPERTY_DEFN_ELEM_delete(property_defns, &elem);
goto end;
}
/* check if property definition is in the cache already */
if ((p = lh_PROPERTY_DEFN_ELEM_retrieve(property_defns, &elem)) != NULL) {
ossl_property_free(*pl);
*pl = p->defn;
goto end;
}
len = strlen(prop);
p = OPENSSL_malloc(sizeof(*p) + len);
if (p != NULL) {
p->prop = p->body;
p->defn = *pl;
memcpy(p->body, prop, len + 1);
old = lh_PROPERTY_DEFN_ELEM_insert(property_defns, p);
if (!ossl_assert(old == NULL))
/* This should not happen. An existing entry is handled above. */
goto end;
if (!lh_PROPERTY_DEFN_ELEM_error(property_defns))
goto end;
}
OPENSSL_free(p);
res = 0;
end:
ossl_lib_ctx_unlock(ctx);
return res;
}

View File

@@ -0,0 +1,17 @@
crypto/property/libcrypto-lib-defn_cache.o: crypto/property/defn_cache.c \
include/openssl/err.h include/openssl/macros.h \
include/openssl/opensslconf.h include/openssl/configuration.h \
include/openssl/opensslv.h include/openssl/e_os2.h \
include/openssl/types.h include/openssl/safestack.h \
include/openssl/stack.h include/openssl/bio.h include/openssl/crypto.h \
include/openssl/cryptoerr.h include/openssl/symhacks.h \
include/openssl/cryptoerr_legacy.h include/openssl/core.h \
include/openssl/bioerr.h include/openssl/lhash.h \
include/internal/propertyerr.h include/internal/property.h \
include/internal/cryptlib.h include/internal/common.h \
include/internal/e_os.h include/internal/numbers.h \
include/internal/nelem.h include/openssl/buffer.h \
include/openssl/buffererr.h include/openssl/asn1.h \
include/openssl/asn1err.h include/openssl/bn.h include/openssl/bnerr.h \
include/internal/core.h crypto/property/property_local.h \
include/crypto/context.h

View File

@@ -0,0 +1,25 @@
crypto/property/libcrypto-lib-property.o: crypto/property/property.c \
include/openssl/crypto.h include/openssl/macros.h \
include/openssl/opensslconf.h include/openssl/configuration.h \
include/openssl/opensslv.h include/openssl/e_os2.h \
include/openssl/safestack.h include/openssl/stack.h \
include/openssl/types.h include/openssl/cryptoerr.h \
include/openssl/symhacks.h include/openssl/cryptoerr_legacy.h \
include/openssl/core.h include/internal/core.h \
include/internal/property.h include/internal/cryptlib.h \
include/internal/common.h include/internal/e_os.h \
include/internal/numbers.h include/internal/nelem.h \
include/openssl/buffer.h include/openssl/buffererr.h \
include/openssl/bio.h include/openssl/bioerr.h include/openssl/asn1.h \
include/openssl/asn1err.h include/openssl/bn.h include/openssl/bnerr.h \
include/openssl/err.h include/openssl/lhash.h \
include/internal/provider.h include/openssl/core_dispatch.h \
include/openssl/indicator.h include/openssl/params.h \
include/internal/dso.h include/internal/dsoerr.h \
include/internal/symhacks.h include/internal/tsan_assist.h \
include/crypto/ctype.h include/openssl/rand.h include/openssl/randerr.h \
include/openssl/evp.h include/openssl/evperr.h include/openssl/objects.h \
include/openssl/obj_mac.h include/openssl/objectserr.h \
include/internal/thread_once.h include/crypto/lhash.h \
include/crypto/sparse_array.h crypto/property/property_local.h \
include/crypto/context.h

View File

@@ -0,0 +1,11 @@
crypto/property/libcrypto-lib-property_err.o: \
crypto/property/property_err.c include/openssl/err.h \
include/openssl/macros.h include/openssl/opensslconf.h \
include/openssl/configuration.h include/openssl/opensslv.h \
include/openssl/e_os2.h include/openssl/types.h \
include/openssl/safestack.h include/openssl/stack.h \
include/openssl/bio.h include/openssl/crypto.h \
include/openssl/cryptoerr.h include/openssl/symhacks.h \
include/openssl/cryptoerr_legacy.h include/openssl/core.h \
include/openssl/bioerr.h include/openssl/lhash.h \
include/internal/propertyerr.h

View File

@@ -0,0 +1,17 @@
crypto/property/libcrypto-lib-property_parse.o: \
crypto/property/property_parse.c include/openssl/err.h \
include/openssl/macros.h include/openssl/opensslconf.h \
include/openssl/configuration.h include/openssl/opensslv.h \
include/openssl/e_os2.h include/openssl/types.h \
include/openssl/safestack.h include/openssl/stack.h \
include/openssl/bio.h include/openssl/crypto.h \
include/openssl/cryptoerr.h include/openssl/symhacks.h \
include/openssl/cryptoerr_legacy.h include/openssl/core.h \
include/openssl/bioerr.h include/openssl/lhash.h \
include/internal/propertyerr.h include/internal/property.h \
include/internal/cryptlib.h include/internal/common.h \
include/internal/e_os.h include/internal/numbers.h \
include/internal/nelem.h include/openssl/buffer.h \
include/openssl/buffererr.h include/openssl/asn1.h \
include/openssl/asn1err.h include/openssl/bn.h include/openssl/bnerr.h \
include/crypto/ctype.h crypto/property/property_local.h

View File

@@ -0,0 +1,17 @@
crypto/property/libcrypto-lib-property_query.o: \
crypto/property/property_query.c include/internal/propertyerr.h \
include/openssl/opensslconf.h include/openssl/configuration.h \
include/openssl/macros.h include/openssl/opensslv.h \
include/openssl/symhacks.h include/openssl/e_os2.h \
include/internal/property.h include/internal/cryptlib.h \
include/internal/common.h include/internal/e_os.h \
include/openssl/crypto.h include/openssl/safestack.h \
include/openssl/stack.h include/openssl/types.h \
include/openssl/cryptoerr.h include/openssl/cryptoerr_legacy.h \
include/openssl/core.h include/internal/numbers.h \
include/internal/nelem.h include/openssl/buffer.h \
include/openssl/buffererr.h include/openssl/bio.h \
include/openssl/bioerr.h include/openssl/asn1.h \
include/openssl/asn1err.h include/openssl/bn.h include/openssl/bnerr.h \
include/openssl/err.h include/openssl/lhash.h \
crypto/property/property_local.h

View File

@@ -0,0 +1,16 @@
crypto/property/libcrypto-lib-property_string.o: \
crypto/property/property_string.c include/openssl/crypto.h \
include/openssl/macros.h include/openssl/opensslconf.h \
include/openssl/configuration.h include/openssl/opensslv.h \
include/openssl/e_os2.h include/openssl/safestack.h \
include/openssl/stack.h include/openssl/types.h \
include/openssl/cryptoerr.h include/openssl/symhacks.h \
include/openssl/cryptoerr_legacy.h include/openssl/core.h \
include/openssl/lhash.h include/openssl/bio.h include/openssl/bioerr.h \
include/crypto/lhash.h crypto/property/property_local.h \
include/internal/property.h include/internal/cryptlib.h \
include/internal/common.h include/internal/e_os.h \
include/internal/numbers.h include/internal/nelem.h \
include/openssl/buffer.h include/openssl/buffererr.h \
include/openssl/asn1.h include/openssl/asn1err.h include/openssl/bn.h \
include/openssl/bnerr.h include/openssl/err.h include/crypto/context.h

View File

@@ -0,0 +1,779 @@
/*
* Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2019, Oracle and/or its affiliates. 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 <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <openssl/crypto.h>
#include "internal/core.h"
#include "internal/property.h"
#include "internal/provider.h"
#include "internal/tsan_assist.h"
#include "crypto/ctype.h"
#include <openssl/lhash.h>
#include <openssl/rand.h>
#include "internal/thread_once.h"
#include "crypto/lhash.h"
#include "crypto/sparse_array.h"
#include "property_local.h"
#include "crypto/context.h"
/*
* The number of elements in the query cache before we initiate a flush.
* If reducing this, also ensure the stochastic test in test/property_test.c
* isn't likely to fail.
*/
#define IMPL_CACHE_FLUSH_THRESHOLD 500
typedef struct {
void *method;
int (*up_ref)(void *);
void (*free)(void *);
} METHOD;
typedef struct {
const OSSL_PROVIDER *provider;
OSSL_PROPERTY_LIST *properties;
METHOD method;
} IMPLEMENTATION;
DEFINE_STACK_OF(IMPLEMENTATION)
typedef struct {
const OSSL_PROVIDER *provider;
const char *query;
METHOD method;
char body[1];
} QUERY;
DEFINE_LHASH_OF_EX(QUERY);
typedef struct {
int nid;
STACK_OF(IMPLEMENTATION) *impls;
LHASH_OF(QUERY) *cache;
} ALGORITHM;
struct ossl_method_store_st {
OSSL_LIB_CTX *ctx;
SPARSE_ARRAY_OF(ALGORITHM) *algs;
/*
* Lock to protect the |algs| array from concurrent writing, when
* individual implementations or queries are inserted. This is used
* by the appropriate functions here.
*/
CRYPTO_RWLOCK *lock;
/*
* Lock to reserve the whole store. This is used when fetching a set
* of algorithms, via these functions, found in crypto/core_fetch.c:
* ossl_method_construct_reserve_store()
* ossl_method_construct_unreserve_store()
*/
CRYPTO_RWLOCK *biglock;
/* query cache specific values */
/* Count of the query cache entries for all algs */
size_t cache_nelem;
/* Flag: 1 if query cache entries for all algs need flushing */
int cache_need_flush;
};
typedef struct {
LHASH_OF(QUERY) *cache;
size_t nelem;
uint32_t seed;
unsigned char using_global_seed;
} IMPL_CACHE_FLUSH;
DEFINE_SPARSE_ARRAY_OF(ALGORITHM);
DEFINE_STACK_OF(ALGORITHM)
typedef struct ossl_global_properties_st {
OSSL_PROPERTY_LIST *list;
#ifndef FIPS_MODULE
unsigned int no_mirrored : 1;
#endif
} OSSL_GLOBAL_PROPERTIES;
static void ossl_method_cache_flush_alg(OSSL_METHOD_STORE *store,
ALGORITHM *alg);
static void ossl_method_cache_flush(OSSL_METHOD_STORE *store, int nid);
/* Global properties are stored per library context */
void ossl_ctx_global_properties_free(void *vglobp)
{
OSSL_GLOBAL_PROPERTIES *globp = vglobp;
if (globp != NULL) {
ossl_property_free(globp->list);
OPENSSL_free(globp);
}
}
void *ossl_ctx_global_properties_new(OSSL_LIB_CTX *ctx)
{
return OPENSSL_zalloc(sizeof(OSSL_GLOBAL_PROPERTIES));
}
OSSL_PROPERTY_LIST **ossl_ctx_global_properties(OSSL_LIB_CTX *libctx,
ossl_unused int loadconfig)
{
OSSL_GLOBAL_PROPERTIES *globp;
#if !defined(FIPS_MODULE) && !defined(OPENSSL_NO_AUTOLOAD_CONFIG)
if (loadconfig && !OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL))
return NULL;
#endif
globp = ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES);
return globp != NULL ? &globp->list : NULL;
}
#ifndef FIPS_MODULE
int ossl_global_properties_no_mirrored(OSSL_LIB_CTX *libctx)
{
OSSL_GLOBAL_PROPERTIES *globp
= ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES);
return globp != NULL && globp->no_mirrored ? 1 : 0;
}
void ossl_global_properties_stop_mirroring(OSSL_LIB_CTX *libctx)
{
OSSL_GLOBAL_PROPERTIES *globp
= ossl_lib_ctx_get_data(libctx, OSSL_LIB_CTX_GLOBAL_PROPERTIES);
if (globp != NULL)
globp->no_mirrored = 1;
}
#endif
static int ossl_method_up_ref(METHOD *method)
{
return (*method->up_ref)(method->method);
}
static void ossl_method_free(METHOD *method)
{
(*method->free)(method->method);
}
static __owur int ossl_property_read_lock(OSSL_METHOD_STORE *p)
{
return p != NULL ? CRYPTO_THREAD_read_lock(p->lock) : 0;
}
static __owur int ossl_property_write_lock(OSSL_METHOD_STORE *p)
{
return p != NULL ? CRYPTO_THREAD_write_lock(p->lock) : 0;
}
static int ossl_property_unlock(OSSL_METHOD_STORE *p)
{
return p != 0 ? CRYPTO_THREAD_unlock(p->lock) : 0;
}
static unsigned long query_hash(const QUERY *a)
{
return OPENSSL_LH_strhash(a->query);
}
static int query_cmp(const QUERY *a, const QUERY *b)
{
int res = strcmp(a->query, b->query);
if (res == 0 && a->provider != NULL && b->provider != NULL)
res = b->provider > a->provider ? 1
: b->provider < a->provider ? -1
: 0;
return res;
}
static void impl_free(IMPLEMENTATION *impl)
{
if (impl != NULL) {
ossl_method_free(&impl->method);
OPENSSL_free(impl);
}
}
static void impl_cache_free(QUERY *elem)
{
if (elem != NULL) {
ossl_method_free(&elem->method);
OPENSSL_free(elem);
}
}
static void impl_cache_flush_alg(ossl_uintmax_t idx, ALGORITHM *alg)
{
lh_QUERY_doall(alg->cache, &impl_cache_free);
lh_QUERY_flush(alg->cache);
}
static void alg_cleanup(ossl_uintmax_t idx, ALGORITHM *a, void *arg)
{
OSSL_METHOD_STORE *store = arg;
if (a != NULL) {
sk_IMPLEMENTATION_pop_free(a->impls, &impl_free);
lh_QUERY_doall(a->cache, &impl_cache_free);
lh_QUERY_free(a->cache);
OPENSSL_free(a);
}
if (store != NULL)
ossl_sa_ALGORITHM_set(store->algs, idx, NULL);
}
/*
* The OSSL_LIB_CTX param here allows access to underlying property data needed
* for computation
*/
OSSL_METHOD_STORE *ossl_method_store_new(OSSL_LIB_CTX *ctx)
{
OSSL_METHOD_STORE *res;
res = OPENSSL_zalloc(sizeof(*res));
if (res != NULL) {
res->ctx = ctx;
if ((res->algs = ossl_sa_ALGORITHM_new()) == NULL
|| (res->lock = CRYPTO_THREAD_lock_new()) == NULL
|| (res->biglock = CRYPTO_THREAD_lock_new()) == NULL) {
ossl_method_store_free(res);
return NULL;
}
}
return res;
}
void ossl_method_store_free(OSSL_METHOD_STORE *store)
{
if (store != NULL) {
if (store->algs != NULL)
ossl_sa_ALGORITHM_doall_arg(store->algs, &alg_cleanup, store);
ossl_sa_ALGORITHM_free(store->algs);
CRYPTO_THREAD_lock_free(store->lock);
CRYPTO_THREAD_lock_free(store->biglock);
OPENSSL_free(store);
}
}
int ossl_method_lock_store(OSSL_METHOD_STORE *store)
{
return store != NULL ? CRYPTO_THREAD_write_lock(store->biglock) : 0;
}
int ossl_method_unlock_store(OSSL_METHOD_STORE *store)
{
return store != NULL ? CRYPTO_THREAD_unlock(store->biglock) : 0;
}
static ALGORITHM *ossl_method_store_retrieve(OSSL_METHOD_STORE *store, int nid)
{
return ossl_sa_ALGORITHM_get(store->algs, nid);
}
static int ossl_method_store_insert(OSSL_METHOD_STORE *store, ALGORITHM *alg)
{
return ossl_sa_ALGORITHM_set(store->algs, alg->nid, alg);
}
int ossl_method_store_add(OSSL_METHOD_STORE *store, const OSSL_PROVIDER *prov,
int nid, const char *properties, void *method,
int (*method_up_ref)(void *),
void (*method_destruct)(void *))
{
ALGORITHM *alg = NULL;
IMPLEMENTATION *impl;
int ret = 0;
int i;
if (nid <= 0 || method == NULL || store == NULL)
return 0;
if (properties == NULL)
properties = "";
if (!ossl_assert(prov != NULL))
return 0;
/* Create new entry */
impl = OPENSSL_malloc(sizeof(*impl));
if (impl == NULL)
return 0;
impl->method.method = method;
impl->method.up_ref = method_up_ref;
impl->method.free = method_destruct;
if (!ossl_method_up_ref(&impl->method)) {
OPENSSL_free(impl);
return 0;
}
impl->provider = prov;
/* Insert into the hash table if required */
if (!ossl_property_write_lock(store)) {
impl_free(impl);
return 0;
}
ossl_method_cache_flush(store, nid);
if ((impl->properties = ossl_prop_defn_get(store->ctx, properties)) == NULL) {
impl->properties = ossl_parse_property(store->ctx, properties);
if (impl->properties == NULL)
goto err;
if (!ossl_prop_defn_set(store->ctx, properties, &impl->properties)) {
ossl_property_free(impl->properties);
impl->properties = NULL;
goto err;
}
}
alg = ossl_method_store_retrieve(store, nid);
if (alg == NULL) {
if ((alg = OPENSSL_zalloc(sizeof(*alg))) == NULL
|| (alg->impls = sk_IMPLEMENTATION_new_null()) == NULL
|| (alg->cache = lh_QUERY_new(&query_hash, &query_cmp)) == NULL)
goto err;
alg->nid = nid;
if (!ossl_method_store_insert(store, alg))
goto err;
}
/* Push onto stack if there isn't one there already */
for (i = 0; i < sk_IMPLEMENTATION_num(alg->impls); i++) {
const IMPLEMENTATION *tmpimpl = sk_IMPLEMENTATION_value(alg->impls, i);
if (tmpimpl->provider == impl->provider
&& tmpimpl->properties == impl->properties)
break;
}
if (i == sk_IMPLEMENTATION_num(alg->impls)
&& sk_IMPLEMENTATION_push(alg->impls, impl))
ret = 1;
ossl_property_unlock(store);
if (ret == 0)
impl_free(impl);
return ret;
err:
ossl_property_unlock(store);
alg_cleanup(0, alg, NULL);
impl_free(impl);
return 0;
}
int ossl_method_store_remove(OSSL_METHOD_STORE *store, int nid,
const void *method)
{
ALGORITHM *alg = NULL;
int i;
if (nid <= 0 || method == NULL || store == NULL)
return 0;
if (!ossl_property_write_lock(store))
return 0;
ossl_method_cache_flush(store, nid);
alg = ossl_method_store_retrieve(store, nid);
if (alg == NULL) {
ossl_property_unlock(store);
return 0;
}
/*
* A sorting find then a delete could be faster but these stacks should be
* relatively small, so we avoid the overhead. Sorting could also surprise
* users when result orderings change (even though they are not guaranteed).
*/
for (i = 0; i < sk_IMPLEMENTATION_num(alg->impls); i++) {
IMPLEMENTATION *impl = sk_IMPLEMENTATION_value(alg->impls, i);
if (impl->method.method == method) {
impl_free(impl);
(void)sk_IMPLEMENTATION_delete(alg->impls, i);
ossl_property_unlock(store);
return 1;
}
}
ossl_property_unlock(store);
return 0;
}
struct alg_cleanup_by_provider_data_st {
OSSL_METHOD_STORE *store;
const OSSL_PROVIDER *prov;
};
static void
alg_cleanup_by_provider(ossl_uintmax_t idx, ALGORITHM *alg, void *arg)
{
struct alg_cleanup_by_provider_data_st *data = arg;
int i, count;
/*
* We walk the stack backwards, to avoid having to deal with stack shifts
* caused by deletion
*/
for (count = 0, i = sk_IMPLEMENTATION_num(alg->impls); i-- > 0;) {
IMPLEMENTATION *impl = sk_IMPLEMENTATION_value(alg->impls, i);
if (impl->provider == data->prov) {
impl_free(impl);
(void)sk_IMPLEMENTATION_delete(alg->impls, i);
count++;
}
}
/*
* If we removed any implementation, we also clear the whole associated
* cache, 'cause that's the sensible thing to do.
* There's no point flushing the cache entries where we didn't remove
* any implementation, though.
*/
if (count > 0)
ossl_method_cache_flush_alg(data->store, alg);
}
int ossl_method_store_remove_all_provided(OSSL_METHOD_STORE *store,
const OSSL_PROVIDER *prov)
{
struct alg_cleanup_by_provider_data_st data;
if (!ossl_property_write_lock(store))
return 0;
data.prov = prov;
data.store = store;
ossl_sa_ALGORITHM_doall_arg(store->algs, &alg_cleanup_by_provider, &data);
ossl_property_unlock(store);
return 1;
}
static void alg_do_one(ALGORITHM *alg, IMPLEMENTATION *impl,
void (*fn)(int id, void *method, void *fnarg),
void *fnarg)
{
fn(alg->nid, impl->method.method, fnarg);
}
static void alg_copy(ossl_uintmax_t idx, ALGORITHM *alg, void *arg)
{
STACK_OF(ALGORITHM) *newalg = arg;
(void)sk_ALGORITHM_push(newalg, alg);
}
void ossl_method_store_do_all(OSSL_METHOD_STORE *store,
void (*fn)(int id, void *method, void *fnarg),
void *fnarg)
{
int i, j;
int numalgs, numimps;
STACK_OF(ALGORITHM) *tmpalgs;
ALGORITHM *alg;
if (store != NULL) {
if (!ossl_property_read_lock(store))
return;
tmpalgs = sk_ALGORITHM_new_reserve(NULL,
ossl_sa_ALGORITHM_num(store->algs));
if (tmpalgs == NULL) {
ossl_property_unlock(store);
return;
}
ossl_sa_ALGORITHM_doall_arg(store->algs, alg_copy, tmpalgs);
ossl_property_unlock(store);
numalgs = sk_ALGORITHM_num(tmpalgs);
for (i = 0; i < numalgs; i++) {
alg = sk_ALGORITHM_value(tmpalgs, i);
numimps = sk_IMPLEMENTATION_num(alg->impls);
for (j = 0; j < numimps; j++)
alg_do_one(alg, sk_IMPLEMENTATION_value(alg->impls, j), fn, fnarg);
}
sk_ALGORITHM_free(tmpalgs);
}
}
int ossl_method_store_fetch(OSSL_METHOD_STORE *store,
int nid, const char *prop_query,
const OSSL_PROVIDER **prov_rw, void **method)
{
OSSL_PROPERTY_LIST **plp;
ALGORITHM *alg;
IMPLEMENTATION *impl, *best_impl = NULL;
OSSL_PROPERTY_LIST *pq = NULL, *p2 = NULL;
const OSSL_PROVIDER *prov = prov_rw != NULL ? *prov_rw : NULL;
int ret = 0;
int j, best = -1, score, optional;
if (nid <= 0 || method == NULL || store == NULL)
return 0;
#if !defined(FIPS_MODULE) && !defined(OPENSSL_NO_AUTOLOAD_CONFIG)
if (ossl_lib_ctx_is_default(store->ctx)
&& !OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL))
return 0;
#endif
/* This only needs to be a read lock, because the query won't create anything */
if (!ossl_property_read_lock(store))
return 0;
alg = ossl_method_store_retrieve(store, nid);
if (alg == NULL) {
ossl_property_unlock(store);
return 0;
}
if (prop_query != NULL)
p2 = pq = ossl_parse_query(store->ctx, prop_query, 0);
plp = ossl_ctx_global_properties(store->ctx, 0);
if (plp != NULL && *plp != NULL) {
if (pq == NULL) {
pq = *plp;
} else {
p2 = ossl_property_merge(pq, *plp);
ossl_property_free(pq);
if (p2 == NULL)
goto fin;
pq = p2;
}
}
if (pq == NULL) {
for (j = 0; j < sk_IMPLEMENTATION_num(alg->impls); j++) {
if ((impl = sk_IMPLEMENTATION_value(alg->impls, j)) != NULL
&& (prov == NULL || impl->provider == prov)) {
best_impl = impl;
ret = 1;
break;
}
}
goto fin;
}
optional = ossl_property_has_optional(pq);
for (j = 0; j < sk_IMPLEMENTATION_num(alg->impls); j++) {
if ((impl = sk_IMPLEMENTATION_value(alg->impls, j)) != NULL
&& (prov == NULL || impl->provider == prov)) {
score = ossl_property_match_count(pq, impl->properties);
if (score > best) {
best_impl = impl;
best = score;
ret = 1;
if (!optional)
goto fin;
}
}
}
fin:
if (ret && ossl_method_up_ref(&best_impl->method)) {
*method = best_impl->method.method;
if (prov_rw != NULL)
*prov_rw = best_impl->provider;
} else {
ret = 0;
}
ossl_property_unlock(store);
ossl_property_free(p2);
return ret;
}
static void ossl_method_cache_flush_alg(OSSL_METHOD_STORE *store,
ALGORITHM *alg)
{
store->cache_nelem -= lh_QUERY_num_items(alg->cache);
impl_cache_flush_alg(0, alg);
}
static void ossl_method_cache_flush(OSSL_METHOD_STORE *store, int nid)
{
ALGORITHM *alg = ossl_method_store_retrieve(store, nid);
if (alg != NULL)
ossl_method_cache_flush_alg(store, alg);
}
int ossl_method_store_cache_flush_all(OSSL_METHOD_STORE *store)
{
if (!ossl_property_write_lock(store))
return 0;
ossl_sa_ALGORITHM_doall(store->algs, &impl_cache_flush_alg);
store->cache_nelem = 0;
ossl_property_unlock(store);
return 1;
}
IMPLEMENT_LHASH_DOALL_ARG(QUERY, IMPL_CACHE_FLUSH);
/*
* Flush an element from the query cache (perhaps).
*
* In order to avoid taking a write lock or using atomic operations
* to keep accurate least recently used (LRU) or least frequently used
* (LFU) information, the procedure used here is to stochastically
* flush approximately half the cache.
*
* This procedure isn't ideal, LRU or LFU would be better. However,
* in normal operation, reaching a full cache would be unexpected.
* It means that no steady state of algorithm queries has been reached.
* That is, it is most likely an attack of some form. A suboptimal clearance
* strategy that doesn't degrade performance of the normal case is
* preferable to a more refined approach that imposes a performance
* impact.
*/
static void impl_cache_flush_cache(QUERY *c, IMPL_CACHE_FLUSH *state)
{
uint32_t n;
/*
* Implement the 32 bit xorshift as suggested by George Marsaglia in:
* https://doi.org/10.18637/jss.v008.i14
*
* This is a very fast PRNG so there is no need to extract bits one at a
* time and use the entire value each time.
*/
n = state->seed;
n ^= n << 13;
n ^= n >> 17;
n ^= n << 5;
state->seed = n;
if ((n & 1) != 0)
impl_cache_free(lh_QUERY_delete(state->cache, c));
else
state->nelem++;
}
static void impl_cache_flush_one_alg(ossl_uintmax_t idx, ALGORITHM *alg,
void *v)
{
IMPL_CACHE_FLUSH *state = (IMPL_CACHE_FLUSH *)v;
unsigned long orig_down_load = lh_QUERY_get_down_load(alg->cache);
state->cache = alg->cache;
lh_QUERY_set_down_load(alg->cache, 0);
lh_QUERY_doall_IMPL_CACHE_FLUSH(state->cache, &impl_cache_flush_cache,
state);
lh_QUERY_set_down_load(alg->cache, orig_down_load);
}
static void ossl_method_cache_flush_some(OSSL_METHOD_STORE *store)
{
IMPL_CACHE_FLUSH state;
static TSAN_QUALIFIER uint32_t global_seed = 1;
state.nelem = 0;
state.using_global_seed = 0;
if ((state.seed = OPENSSL_rdtsc()) == 0) {
/* If there is no timer available, seed another way */
state.using_global_seed = 1;
state.seed = tsan_load(&global_seed);
}
store->cache_need_flush = 0;
ossl_sa_ALGORITHM_doall_arg(store->algs, &impl_cache_flush_one_alg, &state);
store->cache_nelem = state.nelem;
/* Without a timer, update the global seed */
if (state.using_global_seed)
tsan_add(&global_seed, state.seed);
}
int ossl_method_store_cache_get(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov,
int nid, const char *prop_query, void **method)
{
ALGORITHM *alg;
QUERY elem, *r;
int res = 0;
if (nid <= 0 || store == NULL || prop_query == NULL)
return 0;
if (!ossl_property_read_lock(store))
return 0;
alg = ossl_method_store_retrieve(store, nid);
if (alg == NULL)
goto err;
elem.query = prop_query;
elem.provider = prov;
r = lh_QUERY_retrieve(alg->cache, &elem);
if (r == NULL)
goto err;
if (ossl_method_up_ref(&r->method)) {
*method = r->method.method;
res = 1;
}
err:
ossl_property_unlock(store);
return res;
}
int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov,
int nid, const char *prop_query, void *method,
int (*method_up_ref)(void *),
void (*method_destruct)(void *))
{
QUERY elem, *old, *p = NULL;
ALGORITHM *alg;
size_t len;
int res = 1;
if (nid <= 0 || store == NULL || prop_query == NULL)
return 0;
if (!ossl_assert(prov != NULL))
return 0;
if (!ossl_property_write_lock(store))
return 0;
if (store->cache_need_flush)
ossl_method_cache_flush_some(store);
alg = ossl_method_store_retrieve(store, nid);
if (alg == NULL)
goto err;
if (method == NULL) {
elem.query = prop_query;
elem.provider = prov;
if ((old = lh_QUERY_delete(alg->cache, &elem)) != NULL) {
impl_cache_free(old);
store->cache_nelem--;
}
goto end;
}
p = OPENSSL_malloc(sizeof(*p) + (len = strlen(prop_query)));
if (p != NULL) {
p->query = p->body;
p->provider = prov;
p->method.method = method;
p->method.up_ref = method_up_ref;
p->method.free = method_destruct;
if (!ossl_method_up_ref(&p->method))
goto err;
memcpy((char *)p->query, prop_query, len + 1);
if ((old = lh_QUERY_insert(alg->cache, p)) != NULL) {
impl_cache_free(old);
goto end;
}
if (!lh_QUERY_error(alg->cache)) {
if (++store->cache_nelem >= IMPL_CACHE_FLUSH_THRESHOLD)
store->cache_need_flush = 1;
goto end;
}
ossl_method_free(&p->method);
}
err:
res = 0;
OPENSSL_free(p);
end:
ossl_property_unlock(store);
return res;
}

View File

@@ -0,0 +1,46 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2021 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 <openssl/err.h>
#include "internal/propertyerr.h"
#ifndef OPENSSL_NO_ERR
static const ERR_STRING_DATA PROP_str_reasons[] = {
{ERR_PACK(ERR_LIB_PROP, 0, PROP_R_NAME_TOO_LONG), "name too long"},
{ERR_PACK(ERR_LIB_PROP, 0, PROP_R_NOT_AN_ASCII_CHARACTER),
"not an ascii character"},
{ERR_PACK(ERR_LIB_PROP, 0, PROP_R_NOT_AN_HEXADECIMAL_DIGIT),
"not an hexadecimal digit"},
{ERR_PACK(ERR_LIB_PROP, 0, PROP_R_NOT_AN_IDENTIFIER), "not an identifier"},
{ERR_PACK(ERR_LIB_PROP, 0, PROP_R_NOT_AN_OCTAL_DIGIT),
"not an octal digit"},
{ERR_PACK(ERR_LIB_PROP, 0, PROP_R_NOT_A_DECIMAL_DIGIT),
"not a decimal digit"},
{ERR_PACK(ERR_LIB_PROP, 0, PROP_R_NO_MATCHING_STRING_DELIMITER),
"no matching string delimiter"},
{ERR_PACK(ERR_LIB_PROP, 0, PROP_R_NO_VALUE), "no value"},
{ERR_PACK(ERR_LIB_PROP, 0, PROP_R_PARSE_FAILED), "parse failed"},
{ERR_PACK(ERR_LIB_PROP, 0, PROP_R_STRING_TOO_LONG), "string too long"},
{ERR_PACK(ERR_LIB_PROP, 0, PROP_R_TRAILING_CHARACTERS),
"trailing characters"},
{0, NULL}
};
#endif
int ossl_err_load_PROP_strings(void)
{
#ifndef OPENSSL_NO_ERR
if (ERR_reason_error_string(PROP_str_reasons[0].error) == NULL)
ERR_load_strings_const(PROP_str_reasons);
#endif
return 1;
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2019, Oracle and/or its affiliates. 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 <openssl/crypto.h>
#include "internal/property.h"
typedef int OSSL_PROPERTY_IDX;
typedef enum {
OSSL_PROPERTY_OPER_EQ, OSSL_PROPERTY_OPER_NE, OSSL_PROPERTY_OVERRIDE
} OSSL_PROPERTY_OPER;
struct ossl_property_definition_st {
OSSL_PROPERTY_IDX name_idx;
OSSL_PROPERTY_TYPE type;
OSSL_PROPERTY_OPER oper;
unsigned int optional : 1;
union {
int64_t int_val; /* Signed integer */
OSSL_PROPERTY_IDX str_val; /* String */
} v;
};
struct ossl_property_list_st {
int num_properties;
unsigned int has_optional : 1;
OSSL_PROPERTY_DEFINITION properties[1];
};
#define OSSL_PROPERTY_TRUE 1
#define OSSL_PROPERTY_FALSE 2
/* Property string functions */
OSSL_PROPERTY_IDX ossl_property_name(OSSL_LIB_CTX *ctx, const char *s,
int create);
const char *ossl_property_name_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx);
OSSL_PROPERTY_IDX ossl_property_value(OSSL_LIB_CTX *ctx, const char *s,
int create);
const char *ossl_property_value_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx);
/* Property list functions */
void ossl_property_free(OSSL_PROPERTY_LIST *p);
int ossl_property_has_optional(const OSSL_PROPERTY_LIST *query);
/* Property definition cache functions */
OSSL_PROPERTY_LIST *ossl_prop_defn_get(OSSL_LIB_CTX *ctx, const char *prop);
int ossl_prop_defn_set(OSSL_LIB_CTX *ctx, const char *prop,
OSSL_PROPERTY_LIST **pl);

View File

@@ -0,0 +1,763 @@
/*
* Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2019, Oracle and/or its affiliates. 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 <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <openssl/err.h>
#include "internal/propertyerr.h"
#include "internal/property.h"
#include "internal/numbers.h"
#include "crypto/ctype.h"
#include "internal/nelem.h"
#include "property_local.h"
#include "internal/e_os.h"
DEFINE_STACK_OF(OSSL_PROPERTY_DEFINITION)
static const char *skip_space(const char *s)
{
while (ossl_isspace(*s))
s++;
return s;
}
static int match_ch(const char *t[], char m)
{
const char *s = *t;
if (*s == m) {
*t = skip_space(s + 1);
return 1;
}
return 0;
}
#define MATCH(s, m) match(s, m, sizeof(m) - 1)
static int match(const char *t[], const char m[], size_t m_len)
{
const char *s = *t;
if (OPENSSL_strncasecmp(s, m, m_len) == 0) {
*t = skip_space(s + m_len);
return 1;
}
return 0;
}
static int parse_name(OSSL_LIB_CTX *ctx, const char *t[], int create,
OSSL_PROPERTY_IDX *idx)
{
char name[100];
int err = 0;
size_t i = 0;
const char *s = *t;
int user_name = 0;
for (;;) {
if (!ossl_isalpha(*s)) {
ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_IDENTIFIER,
"HERE-->%s", *t);
return 0;
}
do {
if (i < sizeof(name) - 1)
name[i++] = ossl_tolower(*s);
else
err = 1;
} while (*++s == '_' || ossl_isalnum(*s));
if (*s != '.')
break;
user_name = 1;
if (i < sizeof(name) - 1)
name[i++] = *s;
else
err = 1;
s++;
}
name[i] = '\0';
if (err) {
ERR_raise_data(ERR_LIB_PROP, PROP_R_NAME_TOO_LONG, "HERE-->%s", *t);
return 0;
}
*t = skip_space(s);
*idx = ossl_property_name(ctx, name, user_name && create);
return 1;
}
static int parse_number(const char *t[], OSSL_PROPERTY_DEFINITION *res)
{
const char *s = *t;
int64_t v = 0;
do {
if (!ossl_isdigit(*s)) {
ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT,
"HERE-->%s", *t);
return 0;
}
/* overflow check */
if (v > ((INT64_MAX - (*s - '0')) / 10)) {
ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
"Property %s overflows", *t);
return 0;
}
v = v * 10 + (*s++ - '0');
} while (ossl_isdigit(*s));
if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_A_DECIMAL_DIGIT,
"HERE-->%s", *t);
return 0;
}
*t = skip_space(s);
res->type = OSSL_PROPERTY_TYPE_NUMBER;
res->v.int_val = v;
return 1;
}
static int parse_hex(const char *t[], OSSL_PROPERTY_DEFINITION *res)
{
const char *s = *t;
int64_t v = 0;
int sval;
do {
if (ossl_isdigit(*s)) {
sval = *s - '0';
} else if (ossl_isxdigit(*s)) {
sval = ossl_tolower(*s) - 'a' + 10;
} else {
ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT,
"%s", *t);
return 0;
}
if (v > ((INT64_MAX - sval) / 16)) {
ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
"Property %s overflows", *t);
return 0;
}
v <<= 4;
v += sval;
} while (ossl_isxdigit(*++s));
if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_HEXADECIMAL_DIGIT,
"HERE-->%s", *t);
return 0;
}
*t = skip_space(s);
res->type = OSSL_PROPERTY_TYPE_NUMBER;
res->v.int_val = v;
return 1;
}
static int parse_oct(const char *t[], OSSL_PROPERTY_DEFINITION *res)
{
const char *s = *t;
int64_t v = 0;
do {
if (*s == '9' || *s == '8' || !ossl_isdigit(*s)) {
ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT,
"HERE-->%s", *t);
return 0;
}
if (v > ((INT64_MAX - (*s - '0')) / 8)) {
ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
"Property %s overflows", *t);
return 0;
}
v = (v << 3) + (*s - '0');
} while (ossl_isdigit(*++s) && *s != '9' && *s != '8');
if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_OCTAL_DIGIT,
"HERE-->%s", *t);
return 0;
}
*t = skip_space(s);
res->type = OSSL_PROPERTY_TYPE_NUMBER;
res->v.int_val = v;
return 1;
}
static int parse_string(OSSL_LIB_CTX *ctx, const char *t[], char delim,
OSSL_PROPERTY_DEFINITION *res, const int create)
{
char v[1000];
const char *s = *t;
size_t i = 0;
int err = 0;
while (*s != '\0' && *s != delim) {
if (i < sizeof(v) - 1)
v[i++] = *s;
else
err = 1;
s++;
}
if (*s == '\0') {
ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_MATCHING_STRING_DELIMITER,
"HERE-->%c%s", delim, *t);
return 0;
}
v[i] = '\0';
if (err) {
ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);
} else {
res->v.str_val = ossl_property_value(ctx, v, create);
}
*t = skip_space(s + 1);
res->type = OSSL_PROPERTY_TYPE_STRING;
return !err;
}
static int parse_unquoted(OSSL_LIB_CTX *ctx, const char *t[],
OSSL_PROPERTY_DEFINITION *res, const int create)
{
char v[1000];
const char *s = *t;
size_t i = 0;
int err = 0;
if (*s == '\0' || *s == ',')
return 0;
while (ossl_isprint(*s) && !ossl_isspace(*s) && *s != ',') {
if (i < sizeof(v) - 1)
v[i++] = ossl_tolower(*s);
else
err = 1;
s++;
}
if (!ossl_isspace(*s) && *s != '\0' && *s != ',') {
ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_ASCII_CHARACTER,
"HERE-->%s", s);
return 0;
}
v[i] = 0;
if (err)
ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);
else if ((res->v.str_val = ossl_property_value(ctx, v, create)) == 0)
err = 1;
*t = skip_space(s);
res->type = OSSL_PROPERTY_TYPE_STRING;
return !err;
}
static int parse_value(OSSL_LIB_CTX *ctx, const char *t[],
OSSL_PROPERTY_DEFINITION *res, int create)
{
const char *s = *t;
int r = 0;
if (*s == '"' || *s == '\'') {
s++;
r = parse_string(ctx, &s, s[-1], res, create);
} else if (*s == '+') {
s++;
r = parse_number(&s, res);
} else if (*s == '-') {
s++;
r = parse_number(&s, res);
res->v.int_val = -res->v.int_val;
} else if (*s == '0' && s[1] == 'x') {
s += 2;
r = parse_hex(&s, res);
} else if (*s == '0' && ossl_isdigit(s[1])) {
s++;
r = parse_oct(&s, res);
} else if (ossl_isdigit(*s)) {
return parse_number(t, res);
} else if (ossl_isalpha(*s))
return parse_unquoted(ctx, t, res, create);
if (r)
*t = s;
return r;
}
static int pd_compare(const OSSL_PROPERTY_DEFINITION *const *p1,
const OSSL_PROPERTY_DEFINITION *const *p2)
{
const OSSL_PROPERTY_DEFINITION *pd1 = *p1;
const OSSL_PROPERTY_DEFINITION *pd2 = *p2;
if (pd1->name_idx < pd2->name_idx)
return -1;
if (pd1->name_idx > pd2->name_idx)
return 1;
return 0;
}
static void pd_free(OSSL_PROPERTY_DEFINITION *pd)
{
OPENSSL_free(pd);
}
/*
* Convert a stack of property definitions and queries into a fixed array.
* The items are sorted for efficient query. The stack is not freed.
* This function also checks for duplicated names and returns an error if
* any exist.
*/
static OSSL_PROPERTY_LIST *
stack_to_property_list(OSSL_LIB_CTX *ctx,
STACK_OF(OSSL_PROPERTY_DEFINITION) *sk)
{
const int n = sk_OSSL_PROPERTY_DEFINITION_num(sk);
OSSL_PROPERTY_LIST *r;
OSSL_PROPERTY_IDX prev_name_idx = 0;
int i;
r = OPENSSL_malloc(sizeof(*r)
+ (n <= 0 ? 0 : n - 1) * sizeof(r->properties[0]));
if (r != NULL) {
sk_OSSL_PROPERTY_DEFINITION_sort(sk);
r->has_optional = 0;
for (i = 0; i < n; i++) {
r->properties[i] = *sk_OSSL_PROPERTY_DEFINITION_value(sk, i);
r->has_optional |= r->properties[i].optional;
/* Check for duplicated names */
if (i > 0 && r->properties[i].name_idx == prev_name_idx) {
OPENSSL_free(r);
ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
"Duplicated name `%s'",
ossl_property_name_str(ctx, prev_name_idx));
return NULL;
}
prev_name_idx = r->properties[i].name_idx;
}
r->num_properties = n;
}
return r;
}
OSSL_PROPERTY_LIST *ossl_parse_property(OSSL_LIB_CTX *ctx, const char *defn)
{
OSSL_PROPERTY_DEFINITION *prop = NULL;
OSSL_PROPERTY_LIST *res = NULL;
STACK_OF(OSSL_PROPERTY_DEFINITION) *sk;
const char *s = defn;
int done;
if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
return NULL;
s = skip_space(s);
done = *s == '\0';
while (!done) {
const char *start = s;
prop = OPENSSL_malloc(sizeof(*prop));
if (prop == NULL)
goto err;
memset(&prop->v, 0, sizeof(prop->v));
prop->optional = 0;
if (!parse_name(ctx, &s, 1, &prop->name_idx))
goto err;
prop->oper = OSSL_PROPERTY_OPER_EQ;
if (prop->name_idx == 0) {
ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,
"Unknown name HERE-->%s", start);
goto err;
}
if (match_ch(&s, '=')) {
if (!parse_value(ctx, &s, prop, 1)) {
ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_VALUE,
"HERE-->%s", start);
goto err;
}
} else {
/* A name alone means a true Boolean */
prop->type = OSSL_PROPERTY_TYPE_STRING;
prop->v.str_val = OSSL_PROPERTY_TRUE;
}
if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop))
goto err;
prop = NULL;
done = !match_ch(&s, ',');
}
if (*s != '\0') {
ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
"HERE-->%s", s);
goto err;
}
res = stack_to_property_list(ctx, sk);
err:
OPENSSL_free(prop);
sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
return res;
}
OSSL_PROPERTY_LIST *ossl_parse_query(OSSL_LIB_CTX *ctx, const char *s,
int create_values)
{
STACK_OF(OSSL_PROPERTY_DEFINITION) *sk;
OSSL_PROPERTY_LIST *res = NULL;
OSSL_PROPERTY_DEFINITION *prop = NULL;
int done;
if (s == NULL || (sk = sk_OSSL_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)
return NULL;
s = skip_space(s);
done = *s == '\0';
while (!done) {
prop = OPENSSL_malloc(sizeof(*prop));
if (prop == NULL)
goto err;
memset(&prop->v, 0, sizeof(prop->v));
if (match_ch(&s, '-')) {
prop->oper = OSSL_PROPERTY_OVERRIDE;
prop->optional = 0;
if (!parse_name(ctx, &s, 1, &prop->name_idx))
goto err;
goto skip_value;
}
prop->optional = match_ch(&s, '?');
if (!parse_name(ctx, &s, 1, &prop->name_idx))
goto err;
if (match_ch(&s, '=')) {
prop->oper = OSSL_PROPERTY_OPER_EQ;
} else if (MATCH(&s, "!=")) {
prop->oper = OSSL_PROPERTY_OPER_NE;
} else {
/* A name alone is a Boolean comparison for true */
prop->oper = OSSL_PROPERTY_OPER_EQ;
prop->type = OSSL_PROPERTY_TYPE_STRING;
prop->v.str_val = OSSL_PROPERTY_TRUE;
goto skip_value;
}
if (!parse_value(ctx, &s, prop, create_values))
prop->type = OSSL_PROPERTY_TYPE_VALUE_UNDEFINED;
skip_value:
if (!sk_OSSL_PROPERTY_DEFINITION_push(sk, prop))
goto err;
prop = NULL;
done = !match_ch(&s, ',');
}
if (*s != '\0') {
ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,
"HERE-->%s", s);
goto err;
}
res = stack_to_property_list(ctx, sk);
err:
OPENSSL_free(prop);
sk_OSSL_PROPERTY_DEFINITION_pop_free(sk, &pd_free);
return res;
}
/*
* Compare a query against a definition.
* Return the number of clauses matched or -1 if a mandatory clause is false.
*/
int ossl_property_match_count(const OSSL_PROPERTY_LIST *query,
const OSSL_PROPERTY_LIST *defn)
{
const OSSL_PROPERTY_DEFINITION *const q = query->properties;
const OSSL_PROPERTY_DEFINITION *const d = defn->properties;
int i = 0, j = 0, matches = 0;
OSSL_PROPERTY_OPER oper;
while (i < query->num_properties) {
if ((oper = q[i].oper) == OSSL_PROPERTY_OVERRIDE) {
i++;
continue;
}
if (j < defn->num_properties) {
if (q[i].name_idx > d[j].name_idx) { /* skip defn, not in query */
j++;
continue;
}
if (q[i].name_idx == d[j].name_idx) { /* both in defn and query */
const int eq = q[i].type == d[j].type
&& memcmp(&q[i].v, &d[j].v, sizeof(q[i].v)) == 0;
if ((eq && oper == OSSL_PROPERTY_OPER_EQ)
|| (!eq && oper == OSSL_PROPERTY_OPER_NE))
matches++;
else if (!q[i].optional)
return -1;
i++;
j++;
continue;
}
}
/*
* Handle the cases of a missing value and a query with no corresponding
* definition. The former fails for any comparison except inequality,
* the latter is treated as a comparison against the Boolean false.
*/
if (q[i].type == OSSL_PROPERTY_TYPE_VALUE_UNDEFINED) {
if (oper == OSSL_PROPERTY_OPER_NE)
matches++;
else if (!q[i].optional)
return -1;
} else if (q[i].type != OSSL_PROPERTY_TYPE_STRING
|| (oper == OSSL_PROPERTY_OPER_EQ
&& q[i].v.str_val != OSSL_PROPERTY_FALSE)
|| (oper == OSSL_PROPERTY_OPER_NE
&& q[i].v.str_val == OSSL_PROPERTY_FALSE)) {
if (!q[i].optional)
return -1;
} else {
matches++;
}
i++;
}
return matches;
}
void ossl_property_free(OSSL_PROPERTY_LIST *p)
{
OPENSSL_free(p);
}
/*
* Merge two property lists.
* If there is a common name, the one from the first list is used.
*/
OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a,
const OSSL_PROPERTY_LIST *b)
{
const OSSL_PROPERTY_DEFINITION *const ap = a->properties;
const OSSL_PROPERTY_DEFINITION *const bp = b->properties;
const OSSL_PROPERTY_DEFINITION *copy;
OSSL_PROPERTY_LIST *r;
int i, j, n;
const int t = a->num_properties + b->num_properties;
r = OPENSSL_malloc(sizeof(*r)
+ (t == 0 ? 0 : t - 1) * sizeof(r->properties[0]));
if (r == NULL)
return NULL;
r->has_optional = 0;
for (i = j = n = 0; i < a->num_properties || j < b->num_properties; n++) {
if (i >= a->num_properties) {
copy = &bp[j++];
} else if (j >= b->num_properties) {
copy = &ap[i++];
} else if (ap[i].name_idx <= bp[j].name_idx) {
if (ap[i].name_idx == bp[j].name_idx)
j++;
copy = &ap[i++];
} else {
copy = &bp[j++];
}
memcpy(r->properties + n, copy, sizeof(r->properties[0]));
r->has_optional |= copy->optional;
}
r->num_properties = n;
if (n != t)
r = OPENSSL_realloc(r, sizeof(*r) + (n - 1) * sizeof(r->properties[0]));
return r;
}
int ossl_property_parse_init(OSSL_LIB_CTX *ctx)
{
static const char *const predefined_names[] = {
"provider", /* Name of provider (default, legacy, fips) */
"version", /* Version number of this provider */
"fips", /* FIPS validated or FIPS supporting algorithm */
"output", /* Output type for encoders */
"input", /* Input type for decoders */
"structure", /* Structure name for encoders and decoders */
};
size_t i;
for (i = 0; i < OSSL_NELEM(predefined_names); i++)
if (ossl_property_name(ctx, predefined_names[i], 1) == 0)
goto err;
/*
* Pre-populate the two Boolean values. We must do them before any other
* values and in this order so that we get the same index as the global
* OSSL_PROPERTY_TRUE and OSSL_PROPERTY_FALSE values
*/
if ((ossl_property_value(ctx, "yes", 1) != OSSL_PROPERTY_TRUE)
|| (ossl_property_value(ctx, "no", 1) != OSSL_PROPERTY_FALSE))
goto err;
return 1;
err:
return 0;
}
static void put_char(char ch, char **buf, size_t *remain, size_t *needed)
{
if (*remain == 0) {
++*needed;
return;
}
if (*remain == 1)
**buf = '\0';
else
**buf = ch;
++*buf;
++*needed;
--*remain;
}
static void put_str(const char *str, char **buf, size_t *remain, size_t *needed)
{
size_t olen, len, i;
char quote = '\0';
int quotes;
len = olen = strlen(str);
*needed += len;
/*
* Check to see if we need quotes or not.
* Characters that are legal in a PropertyName don't need quoting.
* We simply assume all others require quotes.
*/
for (i = 0; i < len; i++)
if (!ossl_isalnum(str[i]) && str[i] != '.' && str[i] != '_') {
/* Default to single quotes ... */
if (quote == '\0')
quote = '\'';
/* ... but use double quotes if a single is present */
if (str[i] == '\'')
quote = '"';
}
quotes = quote != '\0';
if (*remain == 0) {
*needed += 2 * quotes;
return;
}
if (quotes)
put_char(quote, buf, remain, needed);
if (*remain < len + 1 + quotes)
len = *remain - 1;
if (len > 0) {
memcpy(*buf, str, len);
*buf += len;
*remain -= len;
}
if (quotes)
put_char(quote, buf, remain, needed);
if (len < olen && *remain == 1) {
**buf = '\0';
++*buf;
--*remain;
}
}
static void put_num(int64_t val, char **buf, size_t *remain, size_t *needed)
{
int64_t tmpval = val;
size_t len = 1;
if (tmpval < 0) {
len++;
tmpval = -tmpval;
}
for (; tmpval > 9; len++, tmpval /= 10);
*needed += len;
if (*remain == 0)
return;
BIO_snprintf(*buf, *remain, "%lld", (long long int)val);
if (*remain < len) {
*buf += *remain;
*remain = 0;
} else {
*buf += len;
*remain -= len;
}
}
size_t ossl_property_list_to_string(OSSL_LIB_CTX *ctx,
const OSSL_PROPERTY_LIST *list, char *buf,
size_t bufsize)
{
int i;
const OSSL_PROPERTY_DEFINITION *prop = NULL;
size_t needed = 0;
const char *val;
if (list == NULL) {
if (bufsize > 0)
*buf = '\0';
return 1;
}
if (list->num_properties != 0)
prop = &list->properties[list->num_properties - 1];
for (i = 0; i < list->num_properties; i++, prop--) {
/* Skip invalid names */
if (prop->name_idx == 0)
continue;
if (needed > 0)
put_char(',', &buf, &bufsize, &needed);
if (prop->optional)
put_char('?', &buf, &bufsize, &needed);
else if (prop->oper == OSSL_PROPERTY_OVERRIDE)
put_char('-', &buf, &bufsize, &needed);
val = ossl_property_name_str(ctx, prop->name_idx);
if (val == NULL)
return 0;
put_str(val, &buf, &bufsize, &needed);
switch (prop->oper) {
case OSSL_PROPERTY_OPER_NE:
put_char('!', &buf, &bufsize, &needed);
/* fall through */
case OSSL_PROPERTY_OPER_EQ:
put_char('=', &buf, &bufsize, &needed);
/* put value */
switch (prop->type) {
case OSSL_PROPERTY_TYPE_STRING:
val = ossl_property_value_str(ctx, prop->v.str_val);
if (val == NULL)
return 0;
put_str(val, &buf, &bufsize, &needed);
break;
case OSSL_PROPERTY_TYPE_NUMBER:
put_num(prop->v.int_val, &buf, &bufsize, &needed);
break;
default:
return 0;
}
break;
default:
/* do nothing */
break;
}
}
put_char('\0', &buf, &bufsize, &needed);
return needed;
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2021 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/propertyerr.h"
#include "internal/property.h"
#include "property_local.h"
static int property_idx_cmp(const void *keyp, const void *compare)
{
OSSL_PROPERTY_IDX key = *(const OSSL_PROPERTY_IDX *)keyp;
const OSSL_PROPERTY_DEFINITION *defn =
(const OSSL_PROPERTY_DEFINITION *)compare;
return key - defn->name_idx;
}
const OSSL_PROPERTY_DEFINITION *
ossl_property_find_property(const OSSL_PROPERTY_LIST *list,
OSSL_LIB_CTX *libctx, const char *name)
{
OSSL_PROPERTY_IDX name_idx;
if (list == NULL || name == NULL
|| (name_idx = ossl_property_name(libctx, name, 0)) == 0)
return NULL;
return ossl_bsearch(&name_idx, list->properties, list->num_properties,
sizeof(*list->properties), &property_idx_cmp, 0);
}
OSSL_PROPERTY_TYPE ossl_property_get_type(const OSSL_PROPERTY_DEFINITION *prop)
{
return prop->type;
}
const char *ossl_property_get_string_value(OSSL_LIB_CTX *libctx,
const OSSL_PROPERTY_DEFINITION *prop)
{
const char *value = NULL;
if (prop != NULL && prop->type == OSSL_PROPERTY_TYPE_STRING)
value = ossl_property_value_str(libctx, prop->v.str_val);
return value;
}
int64_t ossl_property_get_number_value(const OSSL_PROPERTY_DEFINITION *prop)
{
int64_t value = 0;
if (prop != NULL && prop->type == OSSL_PROPERTY_TYPE_NUMBER)
value = prop->v.int_val;
return value;
}
/* Does a property query have any optional clauses */
int ossl_property_has_optional(const OSSL_PROPERTY_LIST *query)
{
return query->has_optional ? 1 : 0;
}
int ossl_property_is_enabled(OSSL_LIB_CTX *ctx, const char *property_name,
const OSSL_PROPERTY_LIST *prop_list)
{
const OSSL_PROPERTY_DEFINITION *prop;
prop = ossl_property_find_property(prop_list, ctx, property_name);
/* Do a separate check for override as it does not set type */
if (prop == NULL || prop->optional || prop->oper == OSSL_PROPERTY_OVERRIDE)
return 0;
return (prop->type == OSSL_PROPERTY_TYPE_STRING
&& ((prop->oper == OSSL_PROPERTY_OPER_EQ
&& prop->v.str_val == OSSL_PROPERTY_TRUE)
|| (prop->oper == OSSL_PROPERTY_OPER_NE
&& prop->v.str_val != OSSL_PROPERTY_TRUE)));
}

View File

@@ -0,0 +1,271 @@
/*
* Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2019, Oracle and/or its affiliates. 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 <string.h>
#include <openssl/crypto.h>
#include <openssl/lhash.h>
#include "crypto/lhash.h"
#include "property_local.h"
#include "crypto/context.h"
/*
* Property strings are a consolidation of all strings seen by the property
* subsystem. There are two name spaces to keep property names separate from
* property values (numeric values are not expected to be cached however).
* They allow a rapid conversion from a string to a unique index and any
* subsequent string comparison can be done via an integer compare.
*
* This implementation uses OpenSSL's standard hash table. There are more
* space and time efficient algorithms if this becomes a bottleneck.
*/
typedef struct {
const char *s;
OSSL_PROPERTY_IDX idx;
char body[1];
} PROPERTY_STRING;
DEFINE_LHASH_OF_EX(PROPERTY_STRING);
typedef LHASH_OF(PROPERTY_STRING) PROP_TABLE;
typedef struct {
CRYPTO_RWLOCK *lock;
PROP_TABLE *prop_names;
PROP_TABLE *prop_values;
OSSL_PROPERTY_IDX prop_name_idx;
OSSL_PROPERTY_IDX prop_value_idx;
#ifndef OPENSSL_SMALL_FOOTPRINT
STACK_OF(OPENSSL_CSTRING) *prop_namelist;
STACK_OF(OPENSSL_CSTRING) *prop_valuelist;
#endif
} PROPERTY_STRING_DATA;
static unsigned long property_hash(const PROPERTY_STRING *a)
{
return OPENSSL_LH_strhash(a->s);
}
static int property_cmp(const PROPERTY_STRING *a, const PROPERTY_STRING *b)
{
return strcmp(a->s, b->s);
}
static void property_free(PROPERTY_STRING *ps)
{
OPENSSL_free(ps);
}
static void property_table_free(PROP_TABLE **pt)
{
PROP_TABLE *t = *pt;
if (t != NULL) {
lh_PROPERTY_STRING_doall(t, &property_free);
lh_PROPERTY_STRING_free(t);
*pt = NULL;
}
}
void ossl_property_string_data_free(void *vpropdata)
{
PROPERTY_STRING_DATA *propdata = vpropdata;
if (propdata == NULL)
return;
CRYPTO_THREAD_lock_free(propdata->lock);
property_table_free(&propdata->prop_names);
property_table_free(&propdata->prop_values);
#ifndef OPENSSL_SMALL_FOOTPRINT
sk_OPENSSL_CSTRING_free(propdata->prop_namelist);
sk_OPENSSL_CSTRING_free(propdata->prop_valuelist);
propdata->prop_namelist = propdata->prop_valuelist = NULL;
#endif
propdata->prop_name_idx = propdata->prop_value_idx = 0;
OPENSSL_free(propdata);
}
void *ossl_property_string_data_new(OSSL_LIB_CTX *ctx) {
PROPERTY_STRING_DATA *propdata = OPENSSL_zalloc(sizeof(*propdata));
if (propdata == NULL)
return NULL;
propdata->lock = CRYPTO_THREAD_lock_new();
propdata->prop_names = lh_PROPERTY_STRING_new(&property_hash,
&property_cmp);
propdata->prop_values = lh_PROPERTY_STRING_new(&property_hash,
&property_cmp);
#ifndef OPENSSL_SMALL_FOOTPRINT
propdata->prop_namelist = sk_OPENSSL_CSTRING_new_null();
propdata->prop_valuelist = sk_OPENSSL_CSTRING_new_null();
#endif
if (propdata->lock == NULL
#ifndef OPENSSL_SMALL_FOOTPRINT
|| propdata->prop_namelist == NULL
|| propdata->prop_valuelist == NULL
#endif
|| propdata->prop_names == NULL
|| propdata->prop_values == NULL) {
ossl_property_string_data_free(propdata);
return NULL;
}
return propdata;
}
static PROPERTY_STRING *new_property_string(const char *s,
OSSL_PROPERTY_IDX *pidx)
{
const size_t l = strlen(s);
PROPERTY_STRING *ps = OPENSSL_malloc(sizeof(*ps) + l);
if (ps != NULL) {
memcpy(ps->body, s, l + 1);
ps->s = ps->body;
ps->idx = ++*pidx;
if (ps->idx == 0) {
OPENSSL_free(ps);
return NULL;
}
}
return ps;
}
static OSSL_PROPERTY_IDX ossl_property_string(OSSL_LIB_CTX *ctx, int name,
int create, const char *s)
{
PROPERTY_STRING p, *ps, *ps_new;
PROP_TABLE *t;
OSSL_PROPERTY_IDX *pidx;
PROPERTY_STRING_DATA *propdata
= ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX);
if (propdata == NULL)
return 0;
t = name ? propdata->prop_names : propdata->prop_values;
p.s = s;
if (!CRYPTO_THREAD_read_lock(propdata->lock)) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_READ_LOCK);
return 0;
}
ps = lh_PROPERTY_STRING_retrieve(t, &p);
if (ps == NULL && create) {
CRYPTO_THREAD_unlock(propdata->lock);
if (!CRYPTO_THREAD_write_lock(propdata->lock)) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
return 0;
}
pidx = name ? &propdata->prop_name_idx : &propdata->prop_value_idx;
ps = lh_PROPERTY_STRING_retrieve(t, &p);
if (ps == NULL && (ps_new = new_property_string(s, pidx)) != NULL) {
#ifndef OPENSSL_SMALL_FOOTPRINT
STACK_OF(OPENSSL_CSTRING) *slist;
slist = name ? propdata->prop_namelist : propdata->prop_valuelist;
if (sk_OPENSSL_CSTRING_push(slist, ps_new->s) <= 0) {
property_free(ps_new);
CRYPTO_THREAD_unlock(propdata->lock);
return 0;
}
#endif
lh_PROPERTY_STRING_insert(t, ps_new);
if (lh_PROPERTY_STRING_error(t)) {
/*-
* Undo the previous push which means also decrementing the
* index and freeing the allocated storage.
*/
#ifndef OPENSSL_SMALL_FOOTPRINT
sk_OPENSSL_CSTRING_pop(slist);
#endif
property_free(ps_new);
--*pidx;
CRYPTO_THREAD_unlock(propdata->lock);
return 0;
}
ps = ps_new;
}
}
CRYPTO_THREAD_unlock(propdata->lock);
return ps != NULL ? ps->idx : 0;
}
#ifdef OPENSSL_SMALL_FOOTPRINT
struct find_str_st {
const char *str;
OSSL_PROPERTY_IDX idx;
};
static void find_str_fn(PROPERTY_STRING *prop, void *vfindstr)
{
struct find_str_st *findstr = vfindstr;
if (prop->idx == findstr->idx)
findstr->str = prop->s;
}
#endif
static const char *ossl_property_str(int name, OSSL_LIB_CTX *ctx,
OSSL_PROPERTY_IDX idx)
{
const char *r;
PROPERTY_STRING_DATA *propdata
= ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX);
if (propdata == NULL)
return NULL;
if (!CRYPTO_THREAD_read_lock(propdata->lock)) {
ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_READ_LOCK);
return NULL;
}
#ifdef OPENSSL_SMALL_FOOTPRINT
{
struct find_str_st findstr;
findstr.str = NULL;
findstr.idx = idx;
lh_PROPERTY_STRING_doall_arg(name ? propdata->prop_names
: propdata->prop_values,
find_str_fn, &findstr);
r = findstr.str;
}
#else
r = sk_OPENSSL_CSTRING_value(name ? propdata->prop_namelist
: propdata->prop_valuelist, idx - 1);
#endif
CRYPTO_THREAD_unlock(propdata->lock);
return r;
}
OSSL_PROPERTY_IDX ossl_property_name(OSSL_LIB_CTX *ctx, const char *s,
int create)
{
return ossl_property_string(ctx, 1, create, s);
}
const char *ossl_property_name_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
{
return ossl_property_str(1, ctx, idx);
}
OSSL_PROPERTY_IDX ossl_property_value(OSSL_LIB_CTX *ctx, const char *s,
int create)
{
return ossl_property_string(ctx, 0, create, s);
}
const char *ossl_property_value_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
{
return ossl_property_str(0, ctx, idx);
}