1*b077aed3SPierre Pronchery /*
2*b077aed3SPierre Pronchery * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved.
3*b077aed3SPierre Pronchery * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
4*b077aed3SPierre Pronchery *
5*b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
6*b077aed3SPierre Pronchery * this file except in compliance with the License. You can obtain a copy
7*b077aed3SPierre Pronchery * in the file LICENSE in the source distribution or at
8*b077aed3SPierre Pronchery * https://www.openssl.org/source/license.html
9*b077aed3SPierre Pronchery */
10*b077aed3SPierre Pronchery
11*b077aed3SPierre Pronchery #include <string.h>
12*b077aed3SPierre Pronchery #include <openssl/crypto.h>
13*b077aed3SPierre Pronchery #include <openssl/lhash.h>
14*b077aed3SPierre Pronchery #include "crypto/lhash.h"
15*b077aed3SPierre Pronchery #include "property_local.h"
16*b077aed3SPierre Pronchery
17*b077aed3SPierre Pronchery /*
18*b077aed3SPierre Pronchery * Property strings are a consolidation of all strings seen by the property
19*b077aed3SPierre Pronchery * subsystem. There are two name spaces to keep property names separate from
20*b077aed3SPierre Pronchery * property values (numeric values are not expected to be cached however).
21*b077aed3SPierre Pronchery * They allow a rapid conversion from a string to a unique index and any
22*b077aed3SPierre Pronchery * subsequent string comparison can be done via an integer compare.
23*b077aed3SPierre Pronchery *
24*b077aed3SPierre Pronchery * This implementation uses OpenSSL's standard hash table. There are more
25*b077aed3SPierre Pronchery * space and time efficient algorithms if this becomes a bottleneck.
26*b077aed3SPierre Pronchery */
27*b077aed3SPierre Pronchery
28*b077aed3SPierre Pronchery typedef struct {
29*b077aed3SPierre Pronchery const char *s;
30*b077aed3SPierre Pronchery OSSL_PROPERTY_IDX idx;
31*b077aed3SPierre Pronchery char body[1];
32*b077aed3SPierre Pronchery } PROPERTY_STRING;
33*b077aed3SPierre Pronchery
34*b077aed3SPierre Pronchery DEFINE_LHASH_OF(PROPERTY_STRING);
35*b077aed3SPierre Pronchery typedef LHASH_OF(PROPERTY_STRING) PROP_TABLE;
36*b077aed3SPierre Pronchery
37*b077aed3SPierre Pronchery typedef struct {
38*b077aed3SPierre Pronchery CRYPTO_RWLOCK *lock;
39*b077aed3SPierre Pronchery PROP_TABLE *prop_names;
40*b077aed3SPierre Pronchery PROP_TABLE *prop_values;
41*b077aed3SPierre Pronchery OSSL_PROPERTY_IDX prop_name_idx;
42*b077aed3SPierre Pronchery OSSL_PROPERTY_IDX prop_value_idx;
43*b077aed3SPierre Pronchery } PROPERTY_STRING_DATA;
44*b077aed3SPierre Pronchery
property_hash(const PROPERTY_STRING * a)45*b077aed3SPierre Pronchery static unsigned long property_hash(const PROPERTY_STRING *a)
46*b077aed3SPierre Pronchery {
47*b077aed3SPierre Pronchery return OPENSSL_LH_strhash(a->s);
48*b077aed3SPierre Pronchery }
49*b077aed3SPierre Pronchery
property_cmp(const PROPERTY_STRING * a,const PROPERTY_STRING * b)50*b077aed3SPierre Pronchery static int property_cmp(const PROPERTY_STRING *a, const PROPERTY_STRING *b)
51*b077aed3SPierre Pronchery {
52*b077aed3SPierre Pronchery return strcmp(a->s, b->s);
53*b077aed3SPierre Pronchery }
54*b077aed3SPierre Pronchery
property_free(PROPERTY_STRING * ps)55*b077aed3SPierre Pronchery static void property_free(PROPERTY_STRING *ps)
56*b077aed3SPierre Pronchery {
57*b077aed3SPierre Pronchery OPENSSL_free(ps);
58*b077aed3SPierre Pronchery }
59*b077aed3SPierre Pronchery
property_table_free(PROP_TABLE ** pt)60*b077aed3SPierre Pronchery static void property_table_free(PROP_TABLE **pt)
61*b077aed3SPierre Pronchery {
62*b077aed3SPierre Pronchery PROP_TABLE *t = *pt;
63*b077aed3SPierre Pronchery
64*b077aed3SPierre Pronchery if (t != NULL) {
65*b077aed3SPierre Pronchery lh_PROPERTY_STRING_doall(t, &property_free);
66*b077aed3SPierre Pronchery lh_PROPERTY_STRING_free(t);
67*b077aed3SPierre Pronchery *pt = NULL;
68*b077aed3SPierre Pronchery }
69*b077aed3SPierre Pronchery }
70*b077aed3SPierre Pronchery
property_string_data_free(void * vpropdata)71*b077aed3SPierre Pronchery static void property_string_data_free(void *vpropdata)
72*b077aed3SPierre Pronchery {
73*b077aed3SPierre Pronchery PROPERTY_STRING_DATA *propdata = vpropdata;
74*b077aed3SPierre Pronchery
75*b077aed3SPierre Pronchery if (propdata == NULL)
76*b077aed3SPierre Pronchery return;
77*b077aed3SPierre Pronchery
78*b077aed3SPierre Pronchery CRYPTO_THREAD_lock_free(propdata->lock);
79*b077aed3SPierre Pronchery property_table_free(&propdata->prop_names);
80*b077aed3SPierre Pronchery property_table_free(&propdata->prop_values);
81*b077aed3SPierre Pronchery propdata->prop_name_idx = propdata->prop_value_idx = 0;
82*b077aed3SPierre Pronchery
83*b077aed3SPierre Pronchery OPENSSL_free(propdata);
84*b077aed3SPierre Pronchery }
85*b077aed3SPierre Pronchery
property_string_data_new(OSSL_LIB_CTX * ctx)86*b077aed3SPierre Pronchery static void *property_string_data_new(OSSL_LIB_CTX *ctx) {
87*b077aed3SPierre Pronchery PROPERTY_STRING_DATA *propdata = OPENSSL_zalloc(sizeof(*propdata));
88*b077aed3SPierre Pronchery
89*b077aed3SPierre Pronchery if (propdata == NULL)
90*b077aed3SPierre Pronchery return NULL;
91*b077aed3SPierre Pronchery
92*b077aed3SPierre Pronchery propdata->lock = CRYPTO_THREAD_lock_new();
93*b077aed3SPierre Pronchery if (propdata->lock == NULL)
94*b077aed3SPierre Pronchery goto err;
95*b077aed3SPierre Pronchery
96*b077aed3SPierre Pronchery propdata->prop_names = lh_PROPERTY_STRING_new(&property_hash,
97*b077aed3SPierre Pronchery &property_cmp);
98*b077aed3SPierre Pronchery if (propdata->prop_names == NULL)
99*b077aed3SPierre Pronchery goto err;
100*b077aed3SPierre Pronchery
101*b077aed3SPierre Pronchery propdata->prop_values = lh_PROPERTY_STRING_new(&property_hash,
102*b077aed3SPierre Pronchery &property_cmp);
103*b077aed3SPierre Pronchery if (propdata->prop_values == NULL)
104*b077aed3SPierre Pronchery goto err;
105*b077aed3SPierre Pronchery
106*b077aed3SPierre Pronchery return propdata;
107*b077aed3SPierre Pronchery
108*b077aed3SPierre Pronchery err:
109*b077aed3SPierre Pronchery property_string_data_free(propdata);
110*b077aed3SPierre Pronchery return NULL;
111*b077aed3SPierre Pronchery }
112*b077aed3SPierre Pronchery
113*b077aed3SPierre Pronchery static const OSSL_LIB_CTX_METHOD property_string_data_method = {
114*b077aed3SPierre Pronchery OSSL_LIB_CTX_METHOD_DEFAULT_PRIORITY,
115*b077aed3SPierre Pronchery property_string_data_new,
116*b077aed3SPierre Pronchery property_string_data_free,
117*b077aed3SPierre Pronchery };
118*b077aed3SPierre Pronchery
new_property_string(const char * s,OSSL_PROPERTY_IDX * pidx)119*b077aed3SPierre Pronchery static PROPERTY_STRING *new_property_string(const char *s,
120*b077aed3SPierre Pronchery OSSL_PROPERTY_IDX *pidx)
121*b077aed3SPierre Pronchery {
122*b077aed3SPierre Pronchery const size_t l = strlen(s);
123*b077aed3SPierre Pronchery PROPERTY_STRING *ps = OPENSSL_malloc(sizeof(*ps) + l);
124*b077aed3SPierre Pronchery
125*b077aed3SPierre Pronchery if (ps != NULL) {
126*b077aed3SPierre Pronchery memcpy(ps->body, s, l + 1);
127*b077aed3SPierre Pronchery ps->s = ps->body;
128*b077aed3SPierre Pronchery ps->idx = ++*pidx;
129*b077aed3SPierre Pronchery if (ps->idx == 0) {
130*b077aed3SPierre Pronchery OPENSSL_free(ps);
131*b077aed3SPierre Pronchery return NULL;
132*b077aed3SPierre Pronchery }
133*b077aed3SPierre Pronchery }
134*b077aed3SPierre Pronchery return ps;
135*b077aed3SPierre Pronchery }
136*b077aed3SPierre Pronchery
ossl_property_string(CRYPTO_RWLOCK * lock,PROP_TABLE * t,OSSL_PROPERTY_IDX * pidx,const char * s)137*b077aed3SPierre Pronchery static OSSL_PROPERTY_IDX ossl_property_string(CRYPTO_RWLOCK *lock,
138*b077aed3SPierre Pronchery PROP_TABLE *t,
139*b077aed3SPierre Pronchery OSSL_PROPERTY_IDX *pidx,
140*b077aed3SPierre Pronchery const char *s)
141*b077aed3SPierre Pronchery {
142*b077aed3SPierre Pronchery PROPERTY_STRING p, *ps, *ps_new;
143*b077aed3SPierre Pronchery
144*b077aed3SPierre Pronchery p.s = s;
145*b077aed3SPierre Pronchery if (!CRYPTO_THREAD_read_lock(lock)) {
146*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_READ_LOCK);
147*b077aed3SPierre Pronchery return 0;
148*b077aed3SPierre Pronchery }
149*b077aed3SPierre Pronchery ps = lh_PROPERTY_STRING_retrieve(t, &p);
150*b077aed3SPierre Pronchery if (ps == NULL && pidx != NULL) {
151*b077aed3SPierre Pronchery CRYPTO_THREAD_unlock(lock);
152*b077aed3SPierre Pronchery if (!CRYPTO_THREAD_write_lock(lock)) {
153*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_WRITE_LOCK);
154*b077aed3SPierre Pronchery return 0;
155*b077aed3SPierre Pronchery }
156*b077aed3SPierre Pronchery ps = lh_PROPERTY_STRING_retrieve(t, &p);
157*b077aed3SPierre Pronchery if (ps == NULL && (ps_new = new_property_string(s, pidx)) != NULL) {
158*b077aed3SPierre Pronchery lh_PROPERTY_STRING_insert(t, ps_new);
159*b077aed3SPierre Pronchery if (lh_PROPERTY_STRING_error(t)) {
160*b077aed3SPierre Pronchery property_free(ps_new);
161*b077aed3SPierre Pronchery CRYPTO_THREAD_unlock(lock);
162*b077aed3SPierre Pronchery return 0;
163*b077aed3SPierre Pronchery }
164*b077aed3SPierre Pronchery ps = ps_new;
165*b077aed3SPierre Pronchery }
166*b077aed3SPierre Pronchery }
167*b077aed3SPierre Pronchery CRYPTO_THREAD_unlock(lock);
168*b077aed3SPierre Pronchery return ps != NULL ? ps->idx : 0;
169*b077aed3SPierre Pronchery }
170*b077aed3SPierre Pronchery
171*b077aed3SPierre Pronchery struct find_str_st {
172*b077aed3SPierre Pronchery const char *str;
173*b077aed3SPierre Pronchery OSSL_PROPERTY_IDX idx;
174*b077aed3SPierre Pronchery };
175*b077aed3SPierre Pronchery
find_str_fn(PROPERTY_STRING * prop,void * vfindstr)176*b077aed3SPierre Pronchery static void find_str_fn(PROPERTY_STRING *prop, void *vfindstr)
177*b077aed3SPierre Pronchery {
178*b077aed3SPierre Pronchery struct find_str_st *findstr = vfindstr;
179*b077aed3SPierre Pronchery
180*b077aed3SPierre Pronchery if (prop->idx == findstr->idx)
181*b077aed3SPierre Pronchery findstr->str = prop->s;
182*b077aed3SPierre Pronchery }
183*b077aed3SPierre Pronchery
ossl_property_str(int name,OSSL_LIB_CTX * ctx,OSSL_PROPERTY_IDX idx)184*b077aed3SPierre Pronchery static const char *ossl_property_str(int name, OSSL_LIB_CTX *ctx,
185*b077aed3SPierre Pronchery OSSL_PROPERTY_IDX idx)
186*b077aed3SPierre Pronchery {
187*b077aed3SPierre Pronchery struct find_str_st findstr;
188*b077aed3SPierre Pronchery PROPERTY_STRING_DATA *propdata
189*b077aed3SPierre Pronchery = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
190*b077aed3SPierre Pronchery &property_string_data_method);
191*b077aed3SPierre Pronchery
192*b077aed3SPierre Pronchery if (propdata == NULL)
193*b077aed3SPierre Pronchery return NULL;
194*b077aed3SPierre Pronchery
195*b077aed3SPierre Pronchery findstr.str = NULL;
196*b077aed3SPierre Pronchery findstr.idx = idx;
197*b077aed3SPierre Pronchery
198*b077aed3SPierre Pronchery if (!CRYPTO_THREAD_read_lock(propdata->lock)) {
199*b077aed3SPierre Pronchery ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_READ_LOCK);
200*b077aed3SPierre Pronchery return NULL;
201*b077aed3SPierre Pronchery }
202*b077aed3SPierre Pronchery lh_PROPERTY_STRING_doall_arg(name ? propdata->prop_names
203*b077aed3SPierre Pronchery : propdata->prop_values,
204*b077aed3SPierre Pronchery find_str_fn, &findstr);
205*b077aed3SPierre Pronchery CRYPTO_THREAD_unlock(propdata->lock);
206*b077aed3SPierre Pronchery
207*b077aed3SPierre Pronchery return findstr.str;
208*b077aed3SPierre Pronchery }
209*b077aed3SPierre Pronchery
ossl_property_name(OSSL_LIB_CTX * ctx,const char * s,int create)210*b077aed3SPierre Pronchery OSSL_PROPERTY_IDX ossl_property_name(OSSL_LIB_CTX *ctx, const char *s,
211*b077aed3SPierre Pronchery int create)
212*b077aed3SPierre Pronchery {
213*b077aed3SPierre Pronchery PROPERTY_STRING_DATA *propdata
214*b077aed3SPierre Pronchery = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
215*b077aed3SPierre Pronchery &property_string_data_method);
216*b077aed3SPierre Pronchery
217*b077aed3SPierre Pronchery if (propdata == NULL)
218*b077aed3SPierre Pronchery return 0;
219*b077aed3SPierre Pronchery return ossl_property_string(propdata->lock, propdata->prop_names,
220*b077aed3SPierre Pronchery create ? &propdata->prop_name_idx : NULL,
221*b077aed3SPierre Pronchery s);
222*b077aed3SPierre Pronchery }
223*b077aed3SPierre Pronchery
ossl_property_name_str(OSSL_LIB_CTX * ctx,OSSL_PROPERTY_IDX idx)224*b077aed3SPierre Pronchery const char *ossl_property_name_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
225*b077aed3SPierre Pronchery {
226*b077aed3SPierre Pronchery return ossl_property_str(1, ctx, idx);
227*b077aed3SPierre Pronchery }
228*b077aed3SPierre Pronchery
ossl_property_value(OSSL_LIB_CTX * ctx,const char * s,int create)229*b077aed3SPierre Pronchery OSSL_PROPERTY_IDX ossl_property_value(OSSL_LIB_CTX *ctx, const char *s,
230*b077aed3SPierre Pronchery int create)
231*b077aed3SPierre Pronchery {
232*b077aed3SPierre Pronchery PROPERTY_STRING_DATA *propdata
233*b077aed3SPierre Pronchery = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX,
234*b077aed3SPierre Pronchery &property_string_data_method);
235*b077aed3SPierre Pronchery
236*b077aed3SPierre Pronchery if (propdata == NULL)
237*b077aed3SPierre Pronchery return 0;
238*b077aed3SPierre Pronchery return ossl_property_string(propdata->lock, propdata->prop_values,
239*b077aed3SPierre Pronchery create ? &propdata->prop_value_idx : NULL,
240*b077aed3SPierre Pronchery s);
241*b077aed3SPierre Pronchery }
242*b077aed3SPierre Pronchery
ossl_property_value_str(OSSL_LIB_CTX * ctx,OSSL_PROPERTY_IDX idx)243*b077aed3SPierre Pronchery const char *ossl_property_value_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx)
244*b077aed3SPierre Pronchery {
245*b077aed3SPierre Pronchery return ossl_property_str(0, ctx, idx);
246*b077aed3SPierre Pronchery }
247