1 /* $NetBSD: engine.c,v 1.5 2023/06/19 21:41:43 christos Exp $ */
2
3 /*
4 * Copyright (c) 2006 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <config.h>
37 #include <krb5/roken.h>
38
39 #include <engine.h>
40
41 #ifdef HAVE_DLFCN_H
42 #include <dlfcn.h>
43 #ifndef RTLD_NOW
44 #define RTLD_NOW 0
45 #endif
46 #endif
47
48 struct hc_engine {
49 int references;
50 char *name;
51 char *id;
52 void (*destroy)(ENGINE *);
53 const RSA_METHOD *rsa;
54 const DH_METHOD *dh;
55 const RAND_METHOD *rand;
56 };
57
58 ENGINE *
ENGINE_new(void)59 ENGINE_new(void)
60 {
61 ENGINE *engine;
62
63 engine = calloc(1, sizeof(*engine));
64 engine->references = 1;
65
66 return engine;
67 }
68
69 int
ENGINE_free(ENGINE * engine)70 ENGINE_free(ENGINE *engine)
71 {
72 return ENGINE_finish(engine);
73 }
74
75 int
ENGINE_finish(ENGINE * engine)76 ENGINE_finish(ENGINE *engine)
77 {
78 if (engine->references-- <= 0)
79 abort();
80 if (engine->references > 0)
81 return 1;
82
83 if (engine->name)
84 free(engine->name);
85 if (engine->id)
86 free(engine->id);
87 if(engine->destroy)
88 (*engine->destroy)(engine);
89
90 memset(engine, 0, sizeof(*engine));
91 engine->references = -1;
92
93
94 free(engine);
95 return 1;
96 }
97
98 int
ENGINE_up_ref(ENGINE * engine)99 ENGINE_up_ref(ENGINE *engine)
100 {
101 if (engine->references < 0)
102 abort();
103 engine->references++;
104 return 1;
105 }
106
107 int
ENGINE_set_id(ENGINE * engine,const char * id)108 ENGINE_set_id(ENGINE *engine, const char *id)
109 {
110 engine->id = strdup(id);
111 return (engine->id == NULL) ? 0 : 1;
112 }
113
114 int
ENGINE_set_name(ENGINE * engine,const char * name)115 ENGINE_set_name(ENGINE *engine, const char *name)
116 {
117 engine->name = strdup(name);
118 return (engine->name == NULL) ? 0 : 1;
119 }
120
121 int
ENGINE_set_RSA(ENGINE * engine,const RSA_METHOD * method)122 ENGINE_set_RSA(ENGINE *engine, const RSA_METHOD *method)
123 {
124 engine->rsa = method;
125 return 1;
126 }
127
128 int
ENGINE_set_DH(ENGINE * engine,const DH_METHOD * method)129 ENGINE_set_DH(ENGINE *engine, const DH_METHOD *method)
130 {
131 engine->dh = method;
132 return 1;
133 }
134
135 int
ENGINE_set_destroy_function(ENGINE * e,void (* destroy)(ENGINE *))136 ENGINE_set_destroy_function(ENGINE *e, void (*destroy)(ENGINE *))
137 {
138 e->destroy = destroy;
139 return 1;
140 }
141
142 const char *
ENGINE_get_id(const ENGINE * engine)143 ENGINE_get_id(const ENGINE *engine)
144 {
145 return engine->id;
146 }
147
148 const char *
ENGINE_get_name(const ENGINE * engine)149 ENGINE_get_name(const ENGINE *engine)
150 {
151 return engine->name;
152 }
153
154 const RSA_METHOD *
ENGINE_get_RSA(const ENGINE * engine)155 ENGINE_get_RSA(const ENGINE *engine)
156 {
157 return engine->rsa;
158 }
159
160 const DH_METHOD *
ENGINE_get_DH(const ENGINE * engine)161 ENGINE_get_DH(const ENGINE *engine)
162 {
163 return engine->dh;
164 }
165
166 const RAND_METHOD *
ENGINE_get_RAND(const ENGINE * engine)167 ENGINE_get_RAND(const ENGINE *engine)
168 {
169 return engine->rand;
170 }
171
172 /*
173 *
174 */
175
176 #define SG_default_engine(type) \
177 static ENGINE *type##_engine; \
178 int \
179 ENGINE_set_default_##type(ENGINE *engine) \
180 { \
181 if (type##_engine) \
182 ENGINE_finish(type##_engine); \
183 type##_engine = engine; \
184 if (type##_engine) \
185 ENGINE_up_ref(type##_engine); \
186 return 1; \
187 } \
188 ENGINE * \
189 ENGINE_get_default_##type(void) \
190 { \
191 if (type##_engine) \
192 ENGINE_up_ref(type##_engine); \
193 return type##_engine; \
194 }
195
196 SG_default_engine(RSA)
197 SG_default_engine(DH)
198
199 #undef SG_default_engine
200
201 /*
202 *
203 */
204
205 static ENGINE **engines;
206 static unsigned int num_engines;
207
208 static int
add_engine(ENGINE * engine)209 add_engine(ENGINE *engine)
210 {
211 ENGINE **d, *dup;
212
213 dup = ENGINE_by_id(engine->id);
214 if (dup)
215 return 0;
216
217 d = realloc(engines, (num_engines + 1) * sizeof(*engines));
218 if (d == NULL)
219 return 1;
220 engines = d;
221 engines[num_engines++] = engine;
222
223 return 1;
224 }
225
226 void
ENGINE_load_builtin_engines(void)227 ENGINE_load_builtin_engines(void)
228 {
229 ENGINE *engine;
230 int ret;
231
232 engine = ENGINE_new();
233 if (engine == NULL)
234 return;
235
236 ENGINE_set_id(engine, "builtin");
237 ENGINE_set_name(engine,
238 "Heimdal crypto builtin (ltm) engine version " PACKAGE_VERSION);
239 ENGINE_set_RSA(engine, RSA_ltm_method());
240 ENGINE_set_DH(engine, DH_ltm_method());
241
242 ret = add_engine(engine);
243 if (ret != 1)
244 ENGINE_finish(engine);
245
246 #ifdef USE_HCRYPTO_TFM
247 /*
248 * TFM
249 */
250
251 engine = ENGINE_new();
252 if (engine == NULL)
253 return;
254
255 ENGINE_set_id(engine, "tfm");
256 ENGINE_set_name(engine,
257 "Heimdal crypto tfm engine version " PACKAGE_VERSION);
258 ENGINE_set_RSA(engine, RSA_tfm_method());
259 ENGINE_set_DH(engine, DH_tfm_method());
260
261 ret = add_engine(engine);
262 if (ret != 1)
263 ENGINE_finish(engine);
264 #endif /* USE_HCRYPTO_TFM */
265
266 #ifdef USE_HCRYPTO_LTM
267 /*
268 * ltm
269 */
270
271 engine = ENGINE_new();
272 if (engine == NULL)
273 return;
274
275 ENGINE_set_id(engine, "ltm");
276 ENGINE_set_name(engine,
277 "Heimdal crypto ltm engine version " PACKAGE_VERSION);
278 ENGINE_set_RSA(engine, RSA_ltm_method());
279 ENGINE_set_DH(engine, DH_ltm_method());
280
281 ret = add_engine(engine);
282 if (ret != 1)
283 ENGINE_finish(engine);
284 #endif
285
286 #ifdef HAVE_GMP
287 /*
288 * gmp
289 */
290
291 engine = ENGINE_new();
292 if (engine == NULL)
293 return;
294
295 ENGINE_set_id(engine, "gmp");
296 ENGINE_set_name(engine,
297 "Heimdal crypto gmp engine version " PACKAGE_VERSION);
298 ENGINE_set_RSA(engine, RSA_gmp_method());
299
300 ret = add_engine(engine);
301 if (ret != 1)
302 ENGINE_finish(engine);
303 #endif
304 }
305
306 ENGINE *
ENGINE_by_dso(const char * path,const char * id)307 ENGINE_by_dso(const char *path, const char *id)
308 {
309 #ifdef HAVE_DLOPEN
310 ENGINE *engine;
311 void *handle;
312 int ret;
313
314 engine = calloc(1, sizeof(*engine));
315 if (engine == NULL)
316 return NULL;
317
318 handle = dlopen(path, RTLD_NOW);
319 if (handle == NULL) {
320 /* printf("error: %s\n", dlerror()); */
321 free(engine);
322 return NULL;
323 }
324
325 {
326 unsigned long version;
327 openssl_v_check v_check;
328
329 v_check = (openssl_v_check)dlsym(handle, "v_check");
330 if (v_check == NULL) {
331 dlclose(handle);
332 free(engine);
333 return NULL;
334 }
335
336 version = (*v_check)(OPENSSL_DYNAMIC_VERSION);
337 if (version == 0) {
338 dlclose(handle);
339 free(engine);
340 return NULL;
341 }
342 }
343
344 {
345 openssl_bind_engine bind_engine;
346
347 bind_engine = (openssl_bind_engine)dlsym(handle, "bind_engine");
348 if (bind_engine == NULL) {
349 dlclose(handle);
350 free(engine);
351 return NULL;
352 }
353
354 ret = (*bind_engine)(engine, id, NULL); /* XXX fix third arg */
355 if (ret != 1) {
356 dlclose(handle);
357 free(engine);
358 return NULL;
359 }
360 }
361
362 ENGINE_up_ref(engine);
363
364 ret = add_engine(engine);
365 if (ret != 1) {
366 dlclose(handle);
367 ENGINE_finish(engine);
368 return NULL;
369 }
370
371 return engine;
372 #else
373 return NULL;
374 #endif
375 }
376
377 ENGINE *
ENGINE_by_id(const char * id)378 ENGINE_by_id(const char *id)
379 {
380 int i;
381
382 for (i = 0; i < num_engines; i++) {
383 if (strcmp(id, engines[i]->id) == 0) {
384 ENGINE_up_ref(engines[i]);
385 return engines[i];
386 }
387 }
388 return NULL;
389 }
390
391 void
ENGINE_add_conf_module(void)392 ENGINE_add_conf_module(void)
393 {
394 }
395