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