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