xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/hcrypto/engine.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
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