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