1109998Smarkm/* crypto/engine/eng_list.c */
2109998Smarkm/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
3109998Smarkm * project 2000.
4109998Smarkm */
5109998Smarkm/* ====================================================================
6109998Smarkm * Copyright (c) 1999-2001 The OpenSSL Project.  All rights reserved.
7109998Smarkm *
8109998Smarkm * Redistribution and use in source and binary forms, with or without
9109998Smarkm * modification, are permitted provided that the following conditions
10109998Smarkm * are met:
11109998Smarkm *
12109998Smarkm * 1. Redistributions of source code must retain the above copyright
13109998Smarkm *    notice, this list of conditions and the following disclaimer.
14109998Smarkm *
15109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
16109998Smarkm *    notice, this list of conditions and the following disclaimer in
17109998Smarkm *    the documentation and/or other materials provided with the
18109998Smarkm *    distribution.
19109998Smarkm *
20109998Smarkm * 3. All advertising materials mentioning features or use of this
21109998Smarkm *    software must display the following acknowledgment:
22109998Smarkm *    "This product includes software developed by the OpenSSL Project
23109998Smarkm *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24109998Smarkm *
25109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26109998Smarkm *    endorse or promote products derived from this software without
27109998Smarkm *    prior written permission. For written permission, please contact
28109998Smarkm *    licensing@OpenSSL.org.
29109998Smarkm *
30109998Smarkm * 5. Products derived from this software may not be called "OpenSSL"
31109998Smarkm *    nor may "OpenSSL" appear in their names without prior written
32109998Smarkm *    permission of the OpenSSL Project.
33109998Smarkm *
34109998Smarkm * 6. Redistributions of any form whatsoever must retain the following
35109998Smarkm *    acknowledgment:
36109998Smarkm *    "This product includes software developed by the OpenSSL Project
37109998Smarkm *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38109998Smarkm *
39109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42109998Smarkm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE.
51109998Smarkm * ====================================================================
52109998Smarkm *
53109998Smarkm * This product includes cryptographic software written by Eric Young
54109998Smarkm * (eay@cryptsoft.com).  This product includes software written by Tim
55109998Smarkm * Hudson (tjh@cryptsoft.com).
56109998Smarkm *
57109998Smarkm */
58160814Ssimon/* ====================================================================
59160814Ssimon * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
60160814Ssimon * ECDH support in OpenSSL originally developed by
61160814Ssimon * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
62160814Ssimon */
63109998Smarkm
64109998Smarkm#include "eng_int.h"
65109998Smarkm
66109998Smarkm/* The linked-list of pointers to engine types. engine_list_head
67109998Smarkm * incorporates an implicit structural reference but engine_list_tail
68109998Smarkm * does not - the latter is a computational niceity and only points
69109998Smarkm * to something that is already pointed to by its predecessor in the
70109998Smarkm * list (or engine_list_head itself). In the same way, the use of the
71109998Smarkm * "prev" pointer in each ENGINE is to save excessive list iteration,
72109998Smarkm * it doesn't correspond to an extra structural reference. Hence,
73109998Smarkm * engine_list_head, and each non-null "next" pointer account for
74109998Smarkm * the list itself assuming exactly 1 structural reference on each
75109998Smarkm * list member. */
76109998Smarkmstatic ENGINE *engine_list_head = NULL;
77109998Smarkmstatic ENGINE *engine_list_tail = NULL;
78109998Smarkm
79109998Smarkm/* This cleanup function is only needed internally. If it should be called, we
80109998Smarkm * register it with the "ENGINE_cleanup()" stack to be called during cleanup. */
81109998Smarkm
82109998Smarkmstatic void engine_list_cleanup(void)
83109998Smarkm	{
84109998Smarkm	ENGINE *iterator = engine_list_head;
85109998Smarkm
86109998Smarkm	while(iterator != NULL)
87109998Smarkm		{
88109998Smarkm		ENGINE_remove(iterator);
89109998Smarkm		iterator = engine_list_head;
90109998Smarkm		}
91109998Smarkm	return;
92109998Smarkm	}
93109998Smarkm
94109998Smarkm/* These static functions starting with a lower case "engine_" always
95109998Smarkm * take place when CRYPTO_LOCK_ENGINE has been locked up. */
96109998Smarkmstatic int engine_list_add(ENGINE *e)
97109998Smarkm	{
98109998Smarkm	int conflict = 0;
99109998Smarkm	ENGINE *iterator = NULL;
100109998Smarkm
101109998Smarkm	if(e == NULL)
102109998Smarkm		{
103109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
104109998Smarkm			ERR_R_PASSED_NULL_PARAMETER);
105109998Smarkm		return 0;
106109998Smarkm		}
107109998Smarkm	iterator = engine_list_head;
108109998Smarkm	while(iterator && !conflict)
109109998Smarkm		{
110109998Smarkm		conflict = (strcmp(iterator->id, e->id) == 0);
111109998Smarkm		iterator = iterator->next;
112109998Smarkm		}
113109998Smarkm	if(conflict)
114109998Smarkm		{
115109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
116109998Smarkm			ENGINE_R_CONFLICTING_ENGINE_ID);
117109998Smarkm		return 0;
118109998Smarkm		}
119109998Smarkm	if(engine_list_head == NULL)
120109998Smarkm		{
121109998Smarkm		/* We are adding to an empty list. */
122109998Smarkm		if(engine_list_tail)
123109998Smarkm			{
124109998Smarkm			ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
125109998Smarkm				ENGINE_R_INTERNAL_LIST_ERROR);
126109998Smarkm			return 0;
127109998Smarkm			}
128109998Smarkm		engine_list_head = e;
129109998Smarkm		e->prev = NULL;
130109998Smarkm		/* The first time the list allocates, we should register the
131109998Smarkm		 * cleanup. */
132109998Smarkm		engine_cleanup_add_last(engine_list_cleanup);
133109998Smarkm		}
134109998Smarkm	else
135109998Smarkm		{
136109998Smarkm		/* We are adding to the tail of an existing list. */
137109998Smarkm		if((engine_list_tail == NULL) ||
138109998Smarkm				(engine_list_tail->next != NULL))
139109998Smarkm			{
140109998Smarkm			ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
141109998Smarkm				ENGINE_R_INTERNAL_LIST_ERROR);
142109998Smarkm			return 0;
143109998Smarkm			}
144109998Smarkm		engine_list_tail->next = e;
145109998Smarkm		e->prev = engine_list_tail;
146109998Smarkm		}
147109998Smarkm	/* Having the engine in the list assumes a structural
148109998Smarkm	 * reference. */
149109998Smarkm	e->struct_ref++;
150109998Smarkm	engine_ref_debug(e, 0, 1)
151109998Smarkm	/* However it came to be, e is the last item in the list. */
152109998Smarkm	engine_list_tail = e;
153109998Smarkm	e->next = NULL;
154109998Smarkm	return 1;
155109998Smarkm	}
156109998Smarkm
157109998Smarkmstatic int engine_list_remove(ENGINE *e)
158109998Smarkm	{
159109998Smarkm	ENGINE *iterator;
160109998Smarkm
161109998Smarkm	if(e == NULL)
162109998Smarkm		{
163109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE,
164109998Smarkm			ERR_R_PASSED_NULL_PARAMETER);
165109998Smarkm		return 0;
166109998Smarkm		}
167109998Smarkm	/* We need to check that e is in our linked list! */
168109998Smarkm	iterator = engine_list_head;
169109998Smarkm	while(iterator && (iterator != e))
170109998Smarkm		iterator = iterator->next;
171109998Smarkm	if(iterator == NULL)
172109998Smarkm		{
173109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE,
174109998Smarkm			ENGINE_R_ENGINE_IS_NOT_IN_LIST);
175109998Smarkm		return 0;
176109998Smarkm		}
177109998Smarkm	/* un-link e from the chain. */
178109998Smarkm	if(e->next)
179109998Smarkm		e->next->prev = e->prev;
180109998Smarkm	if(e->prev)
181109998Smarkm		e->prev->next = e->next;
182109998Smarkm	/* Correct our head/tail if necessary. */
183109998Smarkm	if(engine_list_head == e)
184109998Smarkm		engine_list_head = e->next;
185109998Smarkm	if(engine_list_tail == e)
186109998Smarkm		engine_list_tail = e->prev;
187109998Smarkm	engine_free_util(e, 0);
188109998Smarkm	return 1;
189109998Smarkm	}
190109998Smarkm
191109998Smarkm/* Get the first/last "ENGINE" type available. */
192109998SmarkmENGINE *ENGINE_get_first(void)
193109998Smarkm	{
194109998Smarkm	ENGINE *ret;
195109998Smarkm
196109998Smarkm	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
197109998Smarkm	ret = engine_list_head;
198109998Smarkm	if(ret)
199109998Smarkm		{
200109998Smarkm		ret->struct_ref++;
201109998Smarkm		engine_ref_debug(ret, 0, 1)
202109998Smarkm		}
203109998Smarkm	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
204109998Smarkm	return ret;
205109998Smarkm	}
206109998Smarkm
207109998SmarkmENGINE *ENGINE_get_last(void)
208109998Smarkm	{
209109998Smarkm	ENGINE *ret;
210109998Smarkm
211109998Smarkm	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
212109998Smarkm	ret = engine_list_tail;
213109998Smarkm	if(ret)
214109998Smarkm		{
215109998Smarkm		ret->struct_ref++;
216109998Smarkm		engine_ref_debug(ret, 0, 1)
217109998Smarkm		}
218109998Smarkm	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
219109998Smarkm	return ret;
220109998Smarkm	}
221109998Smarkm
222109998Smarkm/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
223109998SmarkmENGINE *ENGINE_get_next(ENGINE *e)
224109998Smarkm	{
225109998Smarkm	ENGINE *ret = NULL;
226109998Smarkm	if(e == NULL)
227109998Smarkm		{
228109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_GET_NEXT,
229109998Smarkm			ERR_R_PASSED_NULL_PARAMETER);
230109998Smarkm		return 0;
231109998Smarkm		}
232109998Smarkm	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
233109998Smarkm	ret = e->next;
234109998Smarkm	if(ret)
235109998Smarkm		{
236109998Smarkm		/* Return a valid structural refernce to the next ENGINE */
237109998Smarkm		ret->struct_ref++;
238109998Smarkm		engine_ref_debug(ret, 0, 1)
239109998Smarkm		}
240109998Smarkm	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
241109998Smarkm	/* Release the structural reference to the previous ENGINE */
242109998Smarkm	ENGINE_free(e);
243109998Smarkm	return ret;
244109998Smarkm	}
245109998Smarkm
246109998SmarkmENGINE *ENGINE_get_prev(ENGINE *e)
247109998Smarkm	{
248109998Smarkm	ENGINE *ret = NULL;
249109998Smarkm	if(e == NULL)
250109998Smarkm		{
251109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_GET_PREV,
252109998Smarkm			ERR_R_PASSED_NULL_PARAMETER);
253109998Smarkm		return 0;
254109998Smarkm		}
255109998Smarkm	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
256109998Smarkm	ret = e->prev;
257109998Smarkm	if(ret)
258109998Smarkm		{
259109998Smarkm		/* Return a valid structural reference to the next ENGINE */
260109998Smarkm		ret->struct_ref++;
261109998Smarkm		engine_ref_debug(ret, 0, 1)
262109998Smarkm		}
263109998Smarkm	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
264109998Smarkm	/* Release the structural reference to the previous ENGINE */
265109998Smarkm	ENGINE_free(e);
266109998Smarkm	return ret;
267109998Smarkm	}
268109998Smarkm
269109998Smarkm/* Add another "ENGINE" type into the list. */
270109998Smarkmint ENGINE_add(ENGINE *e)
271109998Smarkm	{
272109998Smarkm	int to_return = 1;
273109998Smarkm	if(e == NULL)
274109998Smarkm		{
275109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_ADD,
276109998Smarkm			ERR_R_PASSED_NULL_PARAMETER);
277109998Smarkm		return 0;
278109998Smarkm		}
279109998Smarkm	if((e->id == NULL) || (e->name == NULL))
280109998Smarkm		{
281109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_ADD,
282109998Smarkm			ENGINE_R_ID_OR_NAME_MISSING);
283109998Smarkm		}
284109998Smarkm	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
285109998Smarkm	if(!engine_list_add(e))
286109998Smarkm		{
287109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_ADD,
288109998Smarkm			ENGINE_R_INTERNAL_LIST_ERROR);
289109998Smarkm		to_return = 0;
290109998Smarkm		}
291109998Smarkm	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
292109998Smarkm	return to_return;
293109998Smarkm	}
294109998Smarkm
295109998Smarkm/* Remove an existing "ENGINE" type from the array. */
296109998Smarkmint ENGINE_remove(ENGINE *e)
297109998Smarkm	{
298109998Smarkm	int to_return = 1;
299109998Smarkm	if(e == NULL)
300109998Smarkm		{
301109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_REMOVE,
302109998Smarkm			ERR_R_PASSED_NULL_PARAMETER);
303109998Smarkm		return 0;
304109998Smarkm		}
305109998Smarkm	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
306109998Smarkm	if(!engine_list_remove(e))
307109998Smarkm		{
308109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_REMOVE,
309109998Smarkm			ENGINE_R_INTERNAL_LIST_ERROR);
310109998Smarkm		to_return = 0;
311109998Smarkm		}
312109998Smarkm	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
313109998Smarkm	return to_return;
314109998Smarkm	}
315109998Smarkm
316109998Smarkmstatic void engine_cpy(ENGINE *dest, const ENGINE *src)
317109998Smarkm	{
318109998Smarkm	dest->id = src->id;
319109998Smarkm	dest->name = src->name;
320109998Smarkm#ifndef OPENSSL_NO_RSA
321109998Smarkm	dest->rsa_meth = src->rsa_meth;
322109998Smarkm#endif
323109998Smarkm#ifndef OPENSSL_NO_DSA
324109998Smarkm	dest->dsa_meth = src->dsa_meth;
325109998Smarkm#endif
326109998Smarkm#ifndef OPENSSL_NO_DH
327109998Smarkm	dest->dh_meth = src->dh_meth;
328109998Smarkm#endif
329160814Ssimon#ifndef OPENSSL_NO_ECDH
330160814Ssimon	dest->ecdh_meth = src->ecdh_meth;
331160814Ssimon#endif
332160814Ssimon#ifndef OPENSSL_NO_ECDSA
333160814Ssimon	dest->ecdsa_meth = src->ecdsa_meth;
334160814Ssimon#endif
335109998Smarkm	dest->rand_meth = src->rand_meth;
336160814Ssimon	dest->store_meth = src->store_meth;
337109998Smarkm	dest->ciphers = src->ciphers;
338109998Smarkm	dest->digests = src->digests;
339238405Sjkim	dest->pkey_meths = src->pkey_meths;
340109998Smarkm	dest->destroy = src->destroy;
341109998Smarkm	dest->init = src->init;
342109998Smarkm	dest->finish = src->finish;
343109998Smarkm	dest->ctrl = src->ctrl;
344109998Smarkm	dest->load_privkey = src->load_privkey;
345109998Smarkm	dest->load_pubkey = src->load_pubkey;
346109998Smarkm	dest->cmd_defns = src->cmd_defns;
347109998Smarkm	dest->flags = src->flags;
348109998Smarkm	}
349109998Smarkm
350109998SmarkmENGINE *ENGINE_by_id(const char *id)
351109998Smarkm	{
352109998Smarkm	ENGINE *iterator;
353160814Ssimon	char *load_dir = NULL;
354109998Smarkm	if(id == NULL)
355109998Smarkm		{
356109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_BY_ID,
357109998Smarkm			ERR_R_PASSED_NULL_PARAMETER);
358109998Smarkm		return NULL;
359109998Smarkm		}
360109998Smarkm	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
361109998Smarkm	iterator = engine_list_head;
362109998Smarkm	while(iterator && (strcmp(id, iterator->id) != 0))
363109998Smarkm		iterator = iterator->next;
364109998Smarkm	if(iterator)
365109998Smarkm		{
366109998Smarkm		/* We need to return a structural reference. If this is an
367109998Smarkm		 * ENGINE type that returns copies, make a duplicate - otherwise
368109998Smarkm		 * increment the existing ENGINE's reference count. */
369109998Smarkm		if(iterator->flags & ENGINE_FLAGS_BY_ID_COPY)
370109998Smarkm			{
371109998Smarkm			ENGINE *cp = ENGINE_new();
372109998Smarkm			if(!cp)
373109998Smarkm				iterator = NULL;
374109998Smarkm			else
375109998Smarkm				{
376109998Smarkm				engine_cpy(cp, iterator);
377109998Smarkm				iterator = cp;
378109998Smarkm				}
379109998Smarkm			}
380109998Smarkm		else
381109998Smarkm			{
382109998Smarkm			iterator->struct_ref++;
383109998Smarkm			engine_ref_debug(iterator, 0, 1)
384109998Smarkm			}
385109998Smarkm		}
386109998Smarkm	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
387160814Ssimon#if 0
388109998Smarkm	if(iterator == NULL)
389109998Smarkm		{
390109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_BY_ID,
391109998Smarkm			ENGINE_R_NO_SUCH_ENGINE);
392109998Smarkm		ERR_add_error_data(2, "id=", id);
393109998Smarkm		}
394109998Smarkm	return iterator;
395160814Ssimon#else
396160814Ssimon	/* EEK! Experimental code starts */
397160814Ssimon	if(iterator) return iterator;
398160814Ssimon	/* Prevent infinite recusrion if we're looking for the dynamic engine. */
399160814Ssimon	if (strcmp(id, "dynamic"))
400160814Ssimon		{
401160814Ssimon#ifdef OPENSSL_SYS_VMS
402160814Ssimon		if((load_dir = getenv("OPENSSL_ENGINES")) == 0) load_dir = "SSLROOT:[ENGINES]";
403160814Ssimon#else
404160814Ssimon		if((load_dir = getenv("OPENSSL_ENGINES")) == 0) load_dir = ENGINESDIR;
405160814Ssimon#endif
406160814Ssimon		iterator = ENGINE_by_id("dynamic");
407160814Ssimon		if(!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) ||
408160814Ssimon				!ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) ||
409160814Ssimon				!ENGINE_ctrl_cmd_string(iterator, "DIR_ADD",
410160814Ssimon					load_dir, 0) ||
411279264Sdelphij				!ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) ||
412160814Ssimon				!ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
413160814Ssimon				goto notfound;
414160814Ssimon		return iterator;
415160814Ssimon		}
416160814Ssimonnotfound:
417215697Ssimon	ENGINE_free(iterator);
418160814Ssimon	ENGINEerr(ENGINE_F_ENGINE_BY_ID,ENGINE_R_NO_SUCH_ENGINE);
419160814Ssimon	ERR_add_error_data(2, "id=", id);
420160814Ssimon	return NULL;
421160814Ssimon	/* EEK! Experimental code ends */
422160814Ssimon#endif
423109998Smarkm	}
424109998Smarkm
425109998Smarkmint ENGINE_up_ref(ENGINE *e)
426109998Smarkm	{
427109998Smarkm	if (e == NULL)
428109998Smarkm		{
429109998Smarkm		ENGINEerr(ENGINE_F_ENGINE_UP_REF,ERR_R_PASSED_NULL_PARAMETER);
430109998Smarkm		return 0;
431109998Smarkm		}
432109998Smarkm	CRYPTO_add(&e->struct_ref,1,CRYPTO_LOCK_ENGINE);
433109998Smarkm	return 1;
434109998Smarkm	}
435