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
49struct 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
59ENGINE	*
60ENGINE_new(void)
61{
62    ENGINE *engine;
63
64    engine = calloc(1, sizeof(*engine));
65    engine->references = 1;
66
67    return engine;
68}
69
70int
71ENGINE_free(ENGINE *engine)
72{
73    return ENGINE_finish(engine);
74}
75
76int
77ENGINE_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
99int
100ENGINE_up_ref(ENGINE *engine)
101{
102    if (engine->references < 0)
103	abort();
104    engine->references++;
105    return 1;
106}
107
108int
109ENGINE_set_id(ENGINE *engine, const char *id)
110{
111    engine->id = strdup(id);
112    return (engine->id == NULL) ? 0 : 1;
113}
114
115int
116ENGINE_set_name(ENGINE *engine, const char *name)
117{
118    engine->name = strdup(name);
119    return (engine->name == NULL) ? 0 : 1;
120}
121
122int
123ENGINE_set_RSA(ENGINE *engine, const RSA_METHOD *method)
124{
125    engine->rsa = method;
126    return 1;
127}
128
129int
130ENGINE_set_DH(ENGINE *engine, const DH_METHOD *method)
131{
132    engine->dh = method;
133    return 1;
134}
135
136int
137ENGINE_set_destroy_function(ENGINE *e, void (*destroy)(ENGINE *))
138{
139    e->destroy = destroy;
140    return 1;
141}
142
143const char *
144ENGINE_get_id(const ENGINE *engine)
145{
146    return engine->id;
147}
148
149const char *
150ENGINE_get_name(const ENGINE *engine)
151{
152    return engine->name;
153}
154
155const RSA_METHOD *
156ENGINE_get_RSA(const ENGINE *engine)
157{
158    return engine->rsa;
159}
160
161const DH_METHOD *
162ENGINE_get_DH(const ENGINE *engine)
163{
164    return engine->dh;
165}
166
167const RAND_METHOD *
168ENGINE_get_RAND(const ENGINE *engine)
169{
170    return engine->rand;
171}
172
173/*
174 *
175 */
176
177#define SG_default_engine(type)			\
178static ENGINE *type##_engine;			\
179int						\
180ENGINE_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}						\
189ENGINE *					\
190ENGINE_get_default_##type(void)			\
191{						\
192    if (type##_engine)				\
193	ENGINE_up_ref(type##_engine);		\
194    return type##_engine;			\
195}
196
197SG_default_engine(RSA)
198SG_default_engine(DH)
199
200#undef SG_default_engine
201
202/*
203 *
204 */
205
206static ENGINE **engines;
207static unsigned int num_engines;
208
209static int
210add_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
227void
228ENGINE_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 engine version " PACKAGE_VERSION);
240#ifdef HAVE_CDSA
241    ENGINE_set_DH(engine, DH_cdsa_method());
242    ENGINE_set_RSA(engine, RSA_cdsa_method());
243#elif defined(HEIM_HC_SF)
244    ENGINE_set_RSA(engine, RSA_sf_method());
245    ENGINE_set_DH(engine, DH_sf_method());
246#elif defined(HEIM_HC_LTM)
247    ENGINE_set_RSA(engine, RSA_ltm_method());
248    ENGINE_set_DH(engine, DH_ltm_method());
249#else
250    ENGINE_set_RSA(engine, RSA_tfm_method());
251    ENGINE_set_DH(engine, DH_tfm_method());
252#endif
253
254    ret = add_engine(engine);
255    if (ret != 1)
256	ENGINE_finish(engine);
257
258#ifdef USE_HCRYPTO_TFM
259    /*
260     * TFM
261     */
262
263    engine = ENGINE_new();
264    if (engine == NULL)
265	return;
266
267    ENGINE_set_id(engine, "tfm");
268    ENGINE_set_name(engine,
269		    "Heimdal crypto tfm engine version " PACKAGE_VERSION);
270    ENGINE_set_RSA(engine, RSA_tfm_method());
271    ENGINE_set_DH(engine, DH_tfm_method());
272
273    ret = add_engine(engine);
274    if (ret != 1)
275	ENGINE_finish(engine);
276#endif /* USE_HCRYPTO_TFM */
277
278#ifdef USE_HCRYPTO_LTM
279    /*
280     * ltm
281     */
282
283    engine = ENGINE_new();
284    if (engine == NULL)
285	return;
286
287    ENGINE_set_id(engine, "ltm");
288    ENGINE_set_name(engine,
289		    "Heimdal crypto ltm engine version " PACKAGE_VERSION);
290    ENGINE_set_RSA(engine, RSA_ltm_method());
291    ENGINE_set_DH(engine, DH_ltm_method());
292
293    ret = add_engine(engine);
294    if (ret != 1)
295	ENGINE_finish(engine);
296#endif
297
298#ifdef HAVE_GMP
299    /*
300     * gmp
301     */
302
303    engine = ENGINE_new();
304    if (engine == NULL)
305	return;
306
307    ENGINE_set_id(engine, "gmp");
308    ENGINE_set_name(engine,
309		    "Heimdal crypto gmp engine version " PACKAGE_VERSION);
310    ENGINE_set_RSA(engine, RSA_gmp_method());
311
312    ret = add_engine(engine);
313    if (ret != 1)
314	ENGINE_finish(engine);
315#endif
316}
317
318ENGINE *
319ENGINE_by_dso(const char *path, const char *id)
320{
321#ifdef HAVE_DLOPEN
322    ENGINE *engine;
323    void *handle;
324    int ret;
325
326    engine = calloc(1, sizeof(*engine));
327    if (engine == NULL)
328	return NULL;
329
330    handle = dlopen(path, RTLD_NOW);
331    if (handle == NULL) {
332	/* printf("error: %s\n", dlerror()); */
333	free(engine);
334	return NULL;
335    }
336
337    {
338	unsigned long version;
339	openssl_v_check v_check;
340
341	v_check = (openssl_v_check)dlsym(handle, "v_check");
342	if (v_check == NULL) {
343	    dlclose(handle);
344	    free(engine);
345	    return NULL;
346	}
347
348	version = (*v_check)(OPENSSL_DYNAMIC_VERSION);
349	if (version == 0) {
350	    dlclose(handle);
351	    free(engine);
352	    return NULL;
353	}
354    }
355
356    {
357	openssl_bind_engine bind_engine;
358
359	bind_engine = (openssl_bind_engine)dlsym(handle, "bind_engine");
360	if (bind_engine == NULL) {
361	    dlclose(handle);
362	    free(engine);
363	    return NULL;
364	}
365
366	ret = (*bind_engine)(engine, id, NULL); /* XXX fix third arg */
367	if (ret != 1) {
368	    dlclose(handle);
369	    free(engine);
370	    return NULL;
371	}
372    }
373
374    ENGINE_up_ref(engine);
375
376    ret = add_engine(engine);
377    if (ret != 1) {
378	dlclose(handle);
379	ENGINE_finish(engine);
380	return NULL;
381    }
382
383    return engine;
384#else
385    return NULL;
386#endif
387}
388
389ENGINE *
390ENGINE_by_id(const char *id)
391{
392    size_t i;
393
394    for (i = 0; i < num_engines; i++) {
395	if (strcmp(id, engines[i]->id) == 0) {
396	    ENGINE_up_ref(engines[i]);
397	    return engines[i];
398	}
399    }
400    return NULL;
401}
402
403void
404ENGINE_add_conf_module(void)
405{
406}
407