123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- /*
- * 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);
- }
|