xref: /freebsd/crypto/openssl/crypto/engine/eng_list.c (revision 74bf4e164ba5851606a27d4feff27717452583e5)
1 /* crypto/engine/eng_list.c */
2 /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
3  * project 2000.
4  */
5 /* ====================================================================
6  * Copyright (c) 1999-2001 The OpenSSL Project.  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
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58 
59 #include <openssl/crypto.h>
60 #include "cryptlib.h"
61 #include "eng_int.h"
62 #include <openssl/engine.h>
63 
64 /* The linked-list of pointers to engine types. engine_list_head
65  * incorporates an implicit structural reference but engine_list_tail
66  * does not - the latter is a computational niceity and only points
67  * to something that is already pointed to by its predecessor in the
68  * list (or engine_list_head itself). In the same way, the use of the
69  * "prev" pointer in each ENGINE is to save excessive list iteration,
70  * it doesn't correspond to an extra structural reference. Hence,
71  * engine_list_head, and each non-null "next" pointer account for
72  * the list itself assuming exactly 1 structural reference on each
73  * list member. */
74 static ENGINE *engine_list_head = NULL;
75 static ENGINE *engine_list_tail = NULL;
76 
77 /* This cleanup function is only needed internally. If it should be called, we
78  * register it with the "ENGINE_cleanup()" stack to be called during cleanup. */
79 
80 static void engine_list_cleanup(void)
81 	{
82 	ENGINE *iterator = engine_list_head;
83 
84 	while(iterator != NULL)
85 		{
86 		ENGINE_remove(iterator);
87 		iterator = engine_list_head;
88 		}
89 	return;
90 	}
91 
92 /* These static functions starting with a lower case "engine_" always
93  * take place when CRYPTO_LOCK_ENGINE has been locked up. */
94 static int engine_list_add(ENGINE *e)
95 	{
96 	int conflict = 0;
97 	ENGINE *iterator = NULL;
98 
99 	if(e == NULL)
100 		{
101 		ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
102 			ERR_R_PASSED_NULL_PARAMETER);
103 		return 0;
104 		}
105 	iterator = engine_list_head;
106 	while(iterator && !conflict)
107 		{
108 		conflict = (strcmp(iterator->id, e->id) == 0);
109 		iterator = iterator->next;
110 		}
111 	if(conflict)
112 		{
113 		ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
114 			ENGINE_R_CONFLICTING_ENGINE_ID);
115 		return 0;
116 		}
117 	if(engine_list_head == NULL)
118 		{
119 		/* We are adding to an empty list. */
120 		if(engine_list_tail)
121 			{
122 			ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
123 				ENGINE_R_INTERNAL_LIST_ERROR);
124 			return 0;
125 			}
126 		engine_list_head = e;
127 		e->prev = NULL;
128 		/* The first time the list allocates, we should register the
129 		 * cleanup. */
130 		engine_cleanup_add_last(engine_list_cleanup);
131 		}
132 	else
133 		{
134 		/* We are adding to the tail of an existing list. */
135 		if((engine_list_tail == NULL) ||
136 				(engine_list_tail->next != NULL))
137 			{
138 			ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
139 				ENGINE_R_INTERNAL_LIST_ERROR);
140 			return 0;
141 			}
142 		engine_list_tail->next = e;
143 		e->prev = engine_list_tail;
144 		}
145 	/* Having the engine in the list assumes a structural
146 	 * reference. */
147 	e->struct_ref++;
148 	engine_ref_debug(e, 0, 1)
149 	/* However it came to be, e is the last item in the list. */
150 	engine_list_tail = e;
151 	e->next = NULL;
152 	return 1;
153 	}
154 
155 static int engine_list_remove(ENGINE *e)
156 	{
157 	ENGINE *iterator;
158 
159 	if(e == NULL)
160 		{
161 		ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE,
162 			ERR_R_PASSED_NULL_PARAMETER);
163 		return 0;
164 		}
165 	/* We need to check that e is in our linked list! */
166 	iterator = engine_list_head;
167 	while(iterator && (iterator != e))
168 		iterator = iterator->next;
169 	if(iterator == NULL)
170 		{
171 		ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE,
172 			ENGINE_R_ENGINE_IS_NOT_IN_LIST);
173 		return 0;
174 		}
175 	/* un-link e from the chain. */
176 	if(e->next)
177 		e->next->prev = e->prev;
178 	if(e->prev)
179 		e->prev->next = e->next;
180 	/* Correct our head/tail if necessary. */
181 	if(engine_list_head == e)
182 		engine_list_head = e->next;
183 	if(engine_list_tail == e)
184 		engine_list_tail = e->prev;
185 	engine_free_util(e, 0);
186 	return 1;
187 	}
188 
189 /* Get the first/last "ENGINE" type available. */
190 ENGINE *ENGINE_get_first(void)
191 	{
192 	ENGINE *ret;
193 
194 	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
195 	ret = engine_list_head;
196 	if(ret)
197 		{
198 		ret->struct_ref++;
199 		engine_ref_debug(ret, 0, 1)
200 		}
201 	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
202 	return ret;
203 	}
204 
205 ENGINE *ENGINE_get_last(void)
206 	{
207 	ENGINE *ret;
208 
209 	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
210 	ret = engine_list_tail;
211 	if(ret)
212 		{
213 		ret->struct_ref++;
214 		engine_ref_debug(ret, 0, 1)
215 		}
216 	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
217 	return ret;
218 	}
219 
220 /* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
221 ENGINE *ENGINE_get_next(ENGINE *e)
222 	{
223 	ENGINE *ret = NULL;
224 	if(e == NULL)
225 		{
226 		ENGINEerr(ENGINE_F_ENGINE_GET_NEXT,
227 			ERR_R_PASSED_NULL_PARAMETER);
228 		return 0;
229 		}
230 	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
231 	ret = e->next;
232 	if(ret)
233 		{
234 		/* Return a valid structural refernce to the next ENGINE */
235 		ret->struct_ref++;
236 		engine_ref_debug(ret, 0, 1)
237 		}
238 	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
239 	/* Release the structural reference to the previous ENGINE */
240 	ENGINE_free(e);
241 	return ret;
242 	}
243 
244 ENGINE *ENGINE_get_prev(ENGINE *e)
245 	{
246 	ENGINE *ret = NULL;
247 	if(e == NULL)
248 		{
249 		ENGINEerr(ENGINE_F_ENGINE_GET_PREV,
250 			ERR_R_PASSED_NULL_PARAMETER);
251 		return 0;
252 		}
253 	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
254 	ret = e->prev;
255 	if(ret)
256 		{
257 		/* Return a valid structural reference to the next ENGINE */
258 		ret->struct_ref++;
259 		engine_ref_debug(ret, 0, 1)
260 		}
261 	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
262 	/* Release the structural reference to the previous ENGINE */
263 	ENGINE_free(e);
264 	return ret;
265 	}
266 
267 /* Add another "ENGINE" type into the list. */
268 int ENGINE_add(ENGINE *e)
269 	{
270 	int to_return = 1;
271 	if(e == NULL)
272 		{
273 		ENGINEerr(ENGINE_F_ENGINE_ADD,
274 			ERR_R_PASSED_NULL_PARAMETER);
275 		return 0;
276 		}
277 	if((e->id == NULL) || (e->name == NULL))
278 		{
279 		ENGINEerr(ENGINE_F_ENGINE_ADD,
280 			ENGINE_R_ID_OR_NAME_MISSING);
281 		}
282 	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
283 	if(!engine_list_add(e))
284 		{
285 		ENGINEerr(ENGINE_F_ENGINE_ADD,
286 			ENGINE_R_INTERNAL_LIST_ERROR);
287 		to_return = 0;
288 		}
289 	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
290 	return to_return;
291 	}
292 
293 /* Remove an existing "ENGINE" type from the array. */
294 int ENGINE_remove(ENGINE *e)
295 	{
296 	int to_return = 1;
297 	if(e == NULL)
298 		{
299 		ENGINEerr(ENGINE_F_ENGINE_REMOVE,
300 			ERR_R_PASSED_NULL_PARAMETER);
301 		return 0;
302 		}
303 	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
304 	if(!engine_list_remove(e))
305 		{
306 		ENGINEerr(ENGINE_F_ENGINE_REMOVE,
307 			ENGINE_R_INTERNAL_LIST_ERROR);
308 		to_return = 0;
309 		}
310 	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
311 	return to_return;
312 	}
313 
314 static void engine_cpy(ENGINE *dest, const ENGINE *src)
315 	{
316 	dest->id = src->id;
317 	dest->name = src->name;
318 #ifndef OPENSSL_NO_RSA
319 	dest->rsa_meth = src->rsa_meth;
320 #endif
321 #ifndef OPENSSL_NO_DSA
322 	dest->dsa_meth = src->dsa_meth;
323 #endif
324 #ifndef OPENSSL_NO_DH
325 	dest->dh_meth = src->dh_meth;
326 #endif
327 	dest->rand_meth = src->rand_meth;
328 	dest->ciphers = src->ciphers;
329 	dest->digests = src->digests;
330 	dest->destroy = src->destroy;
331 	dest->init = src->init;
332 	dest->finish = src->finish;
333 	dest->ctrl = src->ctrl;
334 	dest->load_privkey = src->load_privkey;
335 	dest->load_pubkey = src->load_pubkey;
336 	dest->cmd_defns = src->cmd_defns;
337 	dest->flags = src->flags;
338 	}
339 
340 ENGINE *ENGINE_by_id(const char *id)
341 	{
342 	ENGINE *iterator;
343 	if(id == NULL)
344 		{
345 		ENGINEerr(ENGINE_F_ENGINE_BY_ID,
346 			ERR_R_PASSED_NULL_PARAMETER);
347 		return NULL;
348 		}
349 	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
350 	iterator = engine_list_head;
351 	while(iterator && (strcmp(id, iterator->id) != 0))
352 		iterator = iterator->next;
353 	if(iterator)
354 		{
355 		/* We need to return a structural reference. If this is an
356 		 * ENGINE type that returns copies, make a duplicate - otherwise
357 		 * increment the existing ENGINE's reference count. */
358 		if(iterator->flags & ENGINE_FLAGS_BY_ID_COPY)
359 			{
360 			ENGINE *cp = ENGINE_new();
361 			if(!cp)
362 				iterator = NULL;
363 			else
364 				{
365 				engine_cpy(cp, iterator);
366 				iterator = cp;
367 				}
368 			}
369 		else
370 			{
371 			iterator->struct_ref++;
372 			engine_ref_debug(iterator, 0, 1)
373 			}
374 		}
375 	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
376 	if(iterator == NULL)
377 		{
378 		ENGINEerr(ENGINE_F_ENGINE_BY_ID,
379 			ENGINE_R_NO_SUCH_ENGINE);
380 		ERR_add_error_data(2, "id=", id);
381 		}
382 	return iterator;
383 	}
384 
385 int ENGINE_up_ref(ENGINE *e)
386 	{
387 	if (e == NULL)
388 		{
389 		ENGINEerr(ENGINE_F_ENGINE_UP_REF,ERR_R_PASSED_NULL_PARAMETER);
390 		return 0;
391 		}
392 	CRYPTO_add(&e->struct_ref,1,CRYPTO_LOCK_ENGINE);
393 	return 1;
394 	}
395