1 | /* |
2 | * Copyright 2019 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 | |
17 | /* |
18 | * Property strings are a consolidation of all strings seen by the property |
19 | * subsystem. There are two name spaces to keep property names separate from |
20 | * property values (numeric values are not expected to be cached however). |
21 | * They allow a rapid conversion from a string to a unique index and any |
22 | * subsequent string comparison can be done via an integer compare. |
23 | * |
24 | * This implementation uses OpenSSL's standard hash table. There are more |
25 | * space and time efficient algorithms if this becomes a bottleneck. |
26 | */ |
27 | |
28 | typedef struct { |
29 | const char *s; |
30 | OSSL_PROPERTY_IDX idx; |
31 | char body[1]; |
32 | } PROPERTY_STRING; |
33 | |
34 | DEFINE_LHASH_OF(PROPERTY_STRING); |
35 | typedef LHASH_OF(PROPERTY_STRING) PROP_TABLE; |
36 | |
37 | typedef struct { |
38 | PROP_TABLE *prop_names; |
39 | PROP_TABLE *prop_values; |
40 | OSSL_PROPERTY_IDX prop_name_idx; |
41 | OSSL_PROPERTY_IDX prop_value_idx; |
42 | } PROPERTY_STRING_DATA; |
43 | |
44 | static unsigned long property_hash(const PROPERTY_STRING *a) |
45 | { |
46 | return OPENSSL_LH_strhash(a->s); |
47 | } |
48 | |
49 | static int property_cmp(const PROPERTY_STRING *a, const PROPERTY_STRING *b) |
50 | { |
51 | return strcmp(a->s, b->s); |
52 | } |
53 | |
54 | static void property_free(PROPERTY_STRING *ps) |
55 | { |
56 | OPENSSL_free(ps); |
57 | } |
58 | |
59 | static void property_table_free(PROP_TABLE **pt) |
60 | { |
61 | PROP_TABLE *t = *pt; |
62 | |
63 | if (t != NULL) { |
64 | lh_PROPERTY_STRING_doall(t, &property_free); |
65 | lh_PROPERTY_STRING_free(t); |
66 | *pt = NULL; |
67 | } |
68 | } |
69 | |
70 | static void property_string_data_free(void *vpropdata) |
71 | { |
72 | PROPERTY_STRING_DATA *propdata = vpropdata; |
73 | |
74 | if (propdata == NULL) |
75 | return; |
76 | |
77 | property_table_free(&propdata->prop_names); |
78 | property_table_free(&propdata->prop_values); |
79 | propdata->prop_name_idx = propdata->prop_value_idx = 0; |
80 | |
81 | OPENSSL_free(propdata); |
82 | } |
83 | |
84 | static void *property_string_data_new(OPENSSL_CTX *ctx) { |
85 | PROPERTY_STRING_DATA *propdata = OPENSSL_zalloc(sizeof(*propdata)); |
86 | |
87 | if (propdata == NULL) |
88 | return NULL; |
89 | |
90 | propdata->prop_names = lh_PROPERTY_STRING_new(&property_hash, |
91 | &property_cmp); |
92 | if (propdata->prop_names == NULL) |
93 | goto err; |
94 | |
95 | propdata->prop_values = lh_PROPERTY_STRING_new(&property_hash, |
96 | &property_cmp); |
97 | if (propdata->prop_values == NULL) |
98 | goto err; |
99 | |
100 | return propdata; |
101 | |
102 | err: |
103 | property_string_data_free(propdata); |
104 | return NULL; |
105 | } |
106 | |
107 | static const OPENSSL_CTX_METHOD property_string_data_method = { |
108 | property_string_data_new, |
109 | property_string_data_free, |
110 | }; |
111 | |
112 | static PROPERTY_STRING *new_property_string(const char *s, |
113 | OSSL_PROPERTY_IDX *pidx) |
114 | { |
115 | const size_t l = strlen(s); |
116 | PROPERTY_STRING *ps = OPENSSL_malloc(sizeof(*ps) + l); |
117 | |
118 | if (ps != NULL) { |
119 | memcpy(ps->body, s, l + 1); |
120 | ps->s = ps->body; |
121 | ps->idx = ++*pidx; |
122 | if (ps->idx == 0) { |
123 | OPENSSL_free(ps); |
124 | return NULL; |
125 | } |
126 | } |
127 | return ps; |
128 | } |
129 | |
130 | static OSSL_PROPERTY_IDX ossl_property_string(PROP_TABLE *t, |
131 | OSSL_PROPERTY_IDX *pidx, |
132 | const char *s) |
133 | { |
134 | PROPERTY_STRING p, *ps, *ps_new; |
135 | |
136 | p.s = s; |
137 | ps = lh_PROPERTY_STRING_retrieve(t, &p); |
138 | if (ps == NULL && pidx != NULL) |
139 | if ((ps_new = new_property_string(s, pidx)) != NULL) { |
140 | lh_PROPERTY_STRING_insert(t, ps_new); |
141 | if (lh_PROPERTY_STRING_error(t)) { |
142 | property_free(ps_new); |
143 | return 0; |
144 | } |
145 | ps = ps_new; |
146 | } |
147 | return ps != NULL ? ps->idx : 0; |
148 | } |
149 | |
150 | OSSL_PROPERTY_IDX ossl_property_name(OPENSSL_CTX *ctx, const char *s, |
151 | int create) |
152 | { |
153 | PROPERTY_STRING_DATA *propdata |
154 | = openssl_ctx_get_data(ctx, OPENSSL_CTX_PROPERTY_STRING_INDEX, |
155 | &property_string_data_method); |
156 | |
157 | if (propdata == NULL) |
158 | return 0; |
159 | return ossl_property_string(propdata->prop_names, |
160 | create ? &propdata->prop_name_idx : NULL, |
161 | s); |
162 | } |
163 | |
164 | OSSL_PROPERTY_IDX ossl_property_value(OPENSSL_CTX *ctx, const char *s, |
165 | int create) |
166 | { |
167 | PROPERTY_STRING_DATA *propdata |
168 | = openssl_ctx_get_data(ctx, OPENSSL_CTX_PROPERTY_STRING_INDEX, |
169 | &property_string_data_method); |
170 | |
171 | if (propdata == NULL) |
172 | return 0; |
173 | return ossl_property_string(propdata->prop_values, |
174 | create ? &propdata->prop_value_idx : NULL, |
175 | s); |
176 | } |
177 | |