/src/openssl/crypto/property/property_string.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. |
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> |
14 | | #include "crypto/lhash.h" |
15 | | #include "property_local.h" |
16 | | #include "crypto/context.h" |
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 | | |
35 | | DEFINE_LHASH_OF_EX(PROPERTY_STRING); |
36 | | typedef LHASH_OF(PROPERTY_STRING) PROP_TABLE; |
37 | | |
38 | | typedef struct { |
39 | | CRYPTO_RWLOCK *lock; |
40 | | PROP_TABLE *prop_names; |
41 | | PROP_TABLE *prop_values; |
42 | | OSSL_PROPERTY_IDX prop_name_idx; |
43 | | OSSL_PROPERTY_IDX prop_value_idx; |
44 | | #ifndef OPENSSL_SMALL_FOOTPRINT |
45 | | STACK_OF(OPENSSL_CSTRING) *prop_namelist; |
46 | | STACK_OF(OPENSSL_CSTRING) *prop_valuelist; |
47 | | #endif |
48 | | } PROPERTY_STRING_DATA; |
49 | | |
50 | | static unsigned long property_hash(const PROPERTY_STRING *a) |
51 | 71.0k | { |
52 | 71.0k | return OPENSSL_LH_strhash(a->s); |
53 | 71.0k | } |
54 | | |
55 | | static int property_cmp(const PROPERTY_STRING *a, const PROPERTY_STRING *b) |
56 | 70.9k | { |
57 | 70.9k | return strcmp(a->s, b->s); |
58 | 70.9k | } |
59 | | |
60 | | static void property_free(PROPERTY_STRING *ps) |
61 | 37 | { |
62 | 37 | OPENSSL_free(ps); |
63 | 37 | } |
64 | | |
65 | | static void property_table_free(PROP_TABLE **pt) |
66 | 4 | { |
67 | 4 | PROP_TABLE *t = *pt; |
68 | | |
69 | 4 | if (t != NULL) { |
70 | 4 | lh_PROPERTY_STRING_doall(t, &property_free); |
71 | 4 | lh_PROPERTY_STRING_free(t); |
72 | 4 | *pt = NULL; |
73 | 4 | } |
74 | 4 | } |
75 | | |
76 | | void ossl_property_string_data_free(void *vpropdata) |
77 | 2 | { |
78 | 2 | PROPERTY_STRING_DATA *propdata = vpropdata; |
79 | | |
80 | 2 | if (propdata == NULL) |
81 | 0 | return; |
82 | | |
83 | 2 | CRYPTO_THREAD_lock_free(propdata->lock); |
84 | 2 | property_table_free(&propdata->prop_names); |
85 | 2 | property_table_free(&propdata->prop_values); |
86 | 2 | #ifndef OPENSSL_SMALL_FOOTPRINT |
87 | 2 | sk_OPENSSL_CSTRING_free(propdata->prop_namelist); |
88 | 2 | sk_OPENSSL_CSTRING_free(propdata->prop_valuelist); |
89 | 2 | propdata->prop_namelist = propdata->prop_valuelist = NULL; |
90 | 2 | #endif |
91 | 2 | propdata->prop_name_idx = propdata->prop_value_idx = 0; |
92 | | |
93 | 2 | OPENSSL_free(propdata); |
94 | 2 | } |
95 | | |
96 | 4 | void *ossl_property_string_data_new(OSSL_LIB_CTX *ctx) { |
97 | 4 | PROPERTY_STRING_DATA *propdata = OPENSSL_zalloc(sizeof(*propdata)); |
98 | | |
99 | 4 | if (propdata == NULL) |
100 | 0 | return NULL; |
101 | | |
102 | 4 | propdata->lock = CRYPTO_THREAD_lock_new(); |
103 | 4 | propdata->prop_names = lh_PROPERTY_STRING_new(&property_hash, |
104 | 4 | &property_cmp); |
105 | 4 | propdata->prop_values = lh_PROPERTY_STRING_new(&property_hash, |
106 | 4 | &property_cmp); |
107 | 4 | #ifndef OPENSSL_SMALL_FOOTPRINT |
108 | 4 | propdata->prop_namelist = sk_OPENSSL_CSTRING_new_null(); |
109 | 4 | propdata->prop_valuelist = sk_OPENSSL_CSTRING_new_null(); |
110 | 4 | #endif |
111 | 4 | if (propdata->lock == NULL |
112 | 4 | #ifndef OPENSSL_SMALL_FOOTPRINT |
113 | 4 | || propdata->prop_namelist == NULL |
114 | 4 | || propdata->prop_valuelist == NULL |
115 | 4 | #endif |
116 | 4 | || propdata->prop_names == NULL |
117 | 4 | || propdata->prop_values == NULL) { |
118 | 0 | ossl_property_string_data_free(propdata); |
119 | 0 | return NULL; |
120 | 0 | } |
121 | 4 | return propdata; |
122 | 4 | } |
123 | | |
124 | | static PROPERTY_STRING *new_property_string(const char *s, |
125 | | OSSL_PROPERTY_IDX *pidx) |
126 | 53 | { |
127 | 53 | const size_t l = strlen(s); |
128 | 53 | PROPERTY_STRING *ps = OPENSSL_malloc(sizeof(*ps) + l); |
129 | | |
130 | 53 | if (ps != NULL) { |
131 | 53 | memcpy(ps->body, s, l + 1); |
132 | 53 | ps->s = ps->body; |
133 | 53 | ps->idx = ++*pidx; |
134 | 53 | if (ps->idx == 0) { |
135 | 0 | OPENSSL_free(ps); |
136 | 0 | return NULL; |
137 | 0 | } |
138 | 53 | } |
139 | 53 | return ps; |
140 | 53 | } |
141 | | |
142 | | static OSSL_PROPERTY_IDX ossl_property_string(OSSL_LIB_CTX *ctx, int name, |
143 | | int create, const char *s) |
144 | 70.9k | { |
145 | 70.9k | PROPERTY_STRING p, *ps, *ps_new; |
146 | 70.9k | PROP_TABLE *t; |
147 | 70.9k | OSSL_PROPERTY_IDX *pidx; |
148 | 70.9k | PROPERTY_STRING_DATA *propdata |
149 | 70.9k | = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX); |
150 | | |
151 | 70.9k | if (propdata == NULL) |
152 | 0 | return 0; |
153 | | |
154 | 70.9k | t = name ? propdata->prop_names : propdata->prop_values; |
155 | 70.9k | p.s = s; |
156 | 70.9k | if (!CRYPTO_THREAD_read_lock(propdata->lock)) { |
157 | 0 | ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_READ_LOCK); |
158 | 0 | return 0; |
159 | 0 | } |
160 | 70.9k | ps = lh_PROPERTY_STRING_retrieve(t, &p); |
161 | 70.9k | if (ps == NULL && create) { |
162 | 53 | CRYPTO_THREAD_unlock(propdata->lock); |
163 | 53 | if (!CRYPTO_THREAD_write_lock(propdata->lock)) { |
164 | 0 | ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_WRITE_LOCK); |
165 | 0 | return 0; |
166 | 0 | } |
167 | 53 | pidx = name ? &propdata->prop_name_idx : &propdata->prop_value_idx; |
168 | 53 | ps = lh_PROPERTY_STRING_retrieve(t, &p); |
169 | 53 | if (ps == NULL && (ps_new = new_property_string(s, pidx)) != NULL) { |
170 | 53 | #ifndef OPENSSL_SMALL_FOOTPRINT |
171 | 53 | STACK_OF(OPENSSL_CSTRING) *slist; |
172 | | |
173 | 53 | slist = name ? propdata->prop_namelist : propdata->prop_valuelist; |
174 | 53 | if (sk_OPENSSL_CSTRING_push(slist, ps_new->s) <= 0) { |
175 | 0 | property_free(ps_new); |
176 | 0 | CRYPTO_THREAD_unlock(propdata->lock); |
177 | 0 | return 0; |
178 | 0 | } |
179 | 53 | #endif |
180 | 53 | lh_PROPERTY_STRING_insert(t, ps_new); |
181 | 53 | if (lh_PROPERTY_STRING_error(t)) { |
182 | | /*- |
183 | | * Undo the previous push which means also decrementing the |
184 | | * index and freeing the allocated storage. |
185 | | */ |
186 | 0 | #ifndef OPENSSL_SMALL_FOOTPRINT |
187 | 0 | sk_OPENSSL_CSTRING_pop(slist); |
188 | 0 | #endif |
189 | 0 | property_free(ps_new); |
190 | 0 | --*pidx; |
191 | 0 | CRYPTO_THREAD_unlock(propdata->lock); |
192 | 0 | return 0; |
193 | 0 | } |
194 | 53 | ps = ps_new; |
195 | 53 | } |
196 | 53 | } |
197 | 70.9k | CRYPTO_THREAD_unlock(propdata->lock); |
198 | 70.9k | return ps != NULL ? ps->idx : 0; |
199 | 70.9k | } |
200 | | |
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 | | |
216 | | static const char *ossl_property_str(int name, OSSL_LIB_CTX *ctx, |
217 | | OSSL_PROPERTY_IDX idx) |
218 | 62.2k | { |
219 | 62.2k | const char *r; |
220 | 62.2k | PROPERTY_STRING_DATA *propdata |
221 | 62.2k | = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_PROPERTY_STRING_INDEX); |
222 | | |
223 | 62.2k | if (propdata == NULL) |
224 | 0 | return NULL; |
225 | | |
226 | 62.2k | if (!CRYPTO_THREAD_read_lock(propdata->lock)) { |
227 | 0 | ERR_raise(ERR_LIB_CRYPTO, ERR_R_UNABLE_TO_GET_READ_LOCK); |
228 | 0 | return NULL; |
229 | 0 | } |
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 |
243 | 62.2k | r = sk_OPENSSL_CSTRING_value(name ? propdata->prop_namelist |
244 | 62.2k | : propdata->prop_valuelist, idx - 1); |
245 | 62.2k | #endif |
246 | 62.2k | CRYPTO_THREAD_unlock(propdata->lock); |
247 | | |
248 | 62.2k | return r; |
249 | 62.2k | } |
250 | | |
251 | | OSSL_PROPERTY_IDX ossl_property_name(OSSL_LIB_CTX *ctx, const char *s, |
252 | | int create) |
253 | 69.5k | { |
254 | 69.5k | return ossl_property_string(ctx, 1, create, s); |
255 | 69.5k | } |
256 | | |
257 | | const char *ossl_property_name_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx) |
258 | 0 | { |
259 | 0 | return ossl_property_str(1, ctx, idx); |
260 | 0 | } |
261 | | |
262 | | OSSL_PROPERTY_IDX ossl_property_value(OSSL_LIB_CTX *ctx, const char *s, |
263 | | int create) |
264 | 1.44k | { |
265 | 1.44k | return ossl_property_string(ctx, 0, create, s); |
266 | 1.44k | } |
267 | | |
268 | | const char *ossl_property_value_str(OSSL_LIB_CTX *ctx, OSSL_PROPERTY_IDX idx) |
269 | 62.2k | { |
270 | 62.2k | return ossl_property_str(0, ctx, idx); |
271 | 62.2k | } |