eng_ctrl.c revision 127128
1/* crypto/engine/eng_ctrl.c */
2/* ====================================================================
3 * Copyright (c) 1999-2001 The OpenSSL Project.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in
14 *    the documentation and/or other materials provided with the
15 *    distribution.
16 *
17 * 3. All advertising materials mentioning features or use of this
18 *    software must display the following acknowledgment:
19 *    "This product includes software developed by the OpenSSL Project
20 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
21 *
22 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23 *    endorse or promote products derived from this software without
24 *    prior written permission. For written permission, please contact
25 *    licensing@OpenSSL.org.
26 *
27 * 5. Products derived from this software may not be called "OpenSSL"
28 *    nor may "OpenSSL" appear in their names without prior written
29 *    permission of the OpenSSL Project.
30 *
31 * 6. Redistributions of any form whatsoever must retain the following
32 *    acknowledgment:
33 *    "This product includes software developed by the OpenSSL Project
34 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47 * OF THE POSSIBILITY OF SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This product includes cryptographic software written by Eric Young
51 * (eay@cryptsoft.com).  This product includes software written by Tim
52 * Hudson (tjh@cryptsoft.com).
53 *
54 */
55
56#include <openssl/crypto.h>
57#include "cryptlib.h"
58#include "eng_int.h"
59#include <openssl/engine.h>
60
61/* When querying a ENGINE-specific control command's 'description', this string
62 * is used if the ENGINE_CMD_DEFN has cmd_desc set to NULL. */
63static const char *int_no_description = "";
64
65/* These internal functions handle 'CMD'-related control commands when the
66 * ENGINE in question has asked us to take care of it (ie. the ENGINE did not
67 * set the ENGINE_FLAGS_MANUAL_CMD_CTRL flag. */
68
69static int int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN *defn)
70	{
71	if((defn->cmd_num == 0) || (defn->cmd_name == NULL))
72		return 1;
73	return 0;
74	}
75
76static int int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN *defn, const char *s)
77	{
78	int idx = 0;
79	while(!int_ctrl_cmd_is_null(defn) && (strcmp(defn->cmd_name, s) != 0))
80		{
81		idx++;
82		defn++;
83		}
84	if(int_ctrl_cmd_is_null(defn))
85		/* The given name wasn't found */
86		return -1;
87	return idx;
88	}
89
90static int int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN *defn, unsigned int num)
91	{
92	int idx = 0;
93	/* NB: It is stipulated that 'cmd_defn' lists are ordered by cmd_num. So
94	 * our searches don't need to take any longer than necessary. */
95	while(!int_ctrl_cmd_is_null(defn) && (defn->cmd_num < num))
96		{
97		idx++;
98		defn++;
99		}
100	if(defn->cmd_num == num)
101		return idx;
102	/* The given cmd_num wasn't found */
103	return -1;
104	}
105
106static int int_ctrl_helper(ENGINE *e, int cmd, long i, void *p, void (*f)())
107	{
108	int idx;
109	char *s = (char *)p;
110	/* Take care of the easy one first (eg. it requires no searches) */
111	if(cmd == ENGINE_CTRL_GET_FIRST_CMD_TYPE)
112		{
113		if((e->cmd_defns == NULL) || int_ctrl_cmd_is_null(e->cmd_defns))
114			return 0;
115		return e->cmd_defns->cmd_num;
116		}
117	/* One or two commands require that "p" be a valid string buffer */
118	if((cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) ||
119			(cmd == ENGINE_CTRL_GET_NAME_FROM_CMD) ||
120			(cmd == ENGINE_CTRL_GET_DESC_FROM_CMD))
121		{
122		if(s == NULL)
123			{
124			ENGINEerr(ENGINE_F_INT_CTRL_HELPER,
125				ERR_R_PASSED_NULL_PARAMETER);
126			return -1;
127			}
128		}
129	/* Now handle cmd_name -> cmd_num conversion */
130	if(cmd == ENGINE_CTRL_GET_CMD_FROM_NAME)
131		{
132		if((e->cmd_defns == NULL) || ((idx = int_ctrl_cmd_by_name(
133						e->cmd_defns, s)) < 0))
134			{
135			ENGINEerr(ENGINE_F_INT_CTRL_HELPER,
136				ENGINE_R_INVALID_CMD_NAME);
137			return -1;
138			}
139		return e->cmd_defns[idx].cmd_num;
140		}
141	/* For the rest of the commands, the 'long' argument must specify a
142	 * valie command number - so we need to conduct a search. */
143	if((e->cmd_defns == NULL) || ((idx = int_ctrl_cmd_by_num(e->cmd_defns,
144					(unsigned int)i)) < 0))
145		{
146		ENGINEerr(ENGINE_F_INT_CTRL_HELPER,
147			ENGINE_R_INVALID_CMD_NUMBER);
148		return -1;
149		}
150	/* Now the logic splits depending on command type */
151	switch(cmd)
152		{
153	case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
154		idx++;
155		if(int_ctrl_cmd_is_null(e->cmd_defns + idx))
156			/* end-of-list */
157			return 0;
158		else
159			return e->cmd_defns[idx].cmd_num;
160	case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
161		return strlen(e->cmd_defns[idx].cmd_name);
162	case ENGINE_CTRL_GET_NAME_FROM_CMD:
163		return BIO_snprintf(s,strlen(e->cmd_defns[idx].cmd_name) + 1,
164				    "%s", e->cmd_defns[idx].cmd_name);
165	case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
166		if(e->cmd_defns[idx].cmd_desc)
167			return strlen(e->cmd_defns[idx].cmd_desc);
168		return strlen(int_no_description);
169	case ENGINE_CTRL_GET_DESC_FROM_CMD:
170		if(e->cmd_defns[idx].cmd_desc)
171			return BIO_snprintf(s,
172					    strlen(e->cmd_defns[idx].cmd_desc) + 1,
173					    "%s", e->cmd_defns[idx].cmd_desc);
174		return BIO_snprintf(s, strlen(int_no_description) + 1,"%s",
175				    int_no_description);
176	case ENGINE_CTRL_GET_CMD_FLAGS:
177		return e->cmd_defns[idx].cmd_flags;
178		}
179	/* Shouldn't really be here ... */
180	ENGINEerr(ENGINE_F_INT_CTRL_HELPER,ENGINE_R_INTERNAL_LIST_ERROR);
181	return -1;
182	}
183
184int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
185	{
186	int ctrl_exists, ref_exists;
187	if(e == NULL)
188		{
189		ENGINEerr(ENGINE_F_ENGINE_CTRL,ERR_R_PASSED_NULL_PARAMETER);
190		return 0;
191		}
192	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
193	ref_exists = ((e->struct_ref > 0) ? 1 : 0);
194	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
195	ctrl_exists = ((e->ctrl == NULL) ? 0 : 1);
196	if(!ref_exists)
197		{
198		ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_REFERENCE);
199		return 0;
200		}
201	/* Intercept any "root-level" commands before trying to hand them on to
202	 * ctrl() handlers. */
203	switch(cmd)
204		{
205	case ENGINE_CTRL_HAS_CTRL_FUNCTION:
206		return ctrl_exists;
207	case ENGINE_CTRL_GET_FIRST_CMD_TYPE:
208	case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
209	case ENGINE_CTRL_GET_CMD_FROM_NAME:
210	case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
211	case ENGINE_CTRL_GET_NAME_FROM_CMD:
212	case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
213	case ENGINE_CTRL_GET_DESC_FROM_CMD:
214	case ENGINE_CTRL_GET_CMD_FLAGS:
215		if(ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL))
216			return int_ctrl_helper(e,cmd,i,p,f);
217		if(!ctrl_exists)
218			{
219			ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_CONTROL_FUNCTION);
220			/* For these cmd-related functions, failure is indicated
221			 * by a -1 return value (because 0 is used as a valid
222			 * return in some places). */
223			return -1;
224			}
225	default:
226		break;
227		}
228	/* Anything else requires a ctrl() handler to exist. */
229	if(!ctrl_exists)
230		{
231		ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_CONTROL_FUNCTION);
232		return 0;
233		}
234	return e->ctrl(e, cmd, i, p, f);
235	}
236
237int ENGINE_cmd_is_executable(ENGINE *e, int cmd)
238	{
239	int flags;
240	if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, NULL, NULL)) < 0)
241		{
242		ENGINEerr(ENGINE_F_ENGINE_CMD_IS_EXECUTABLE,
243			ENGINE_R_INVALID_CMD_NUMBER);
244		return 0;
245		}
246	if(!(flags & ENGINE_CMD_FLAG_NO_INPUT) &&
247			!(flags & ENGINE_CMD_FLAG_NUMERIC) &&
248			!(flags & ENGINE_CMD_FLAG_STRING))
249		return 0;
250	return 1;
251	}
252
253int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
254        long i, void *p, void (*f)(), int cmd_optional)
255        {
256	int num;
257
258	if((e == NULL) || (cmd_name == NULL))
259		{
260		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
261			ERR_R_PASSED_NULL_PARAMETER);
262		return 0;
263		}
264	if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e,
265					ENGINE_CTRL_GET_CMD_FROM_NAME,
266					0, (void *)cmd_name, NULL)) <= 0))
267		{
268		/* If the command didn't *have* to be supported, we fake
269		 * success. This allows certain settings to be specified for
270		 * multiple ENGINEs and only require a change of ENGINE id
271		 * (without having to selectively apply settings). Eg. changing
272		 * from a hardware device back to the regular software ENGINE
273		 * without editing the config file, etc. */
274		if(cmd_optional)
275			{
276			ERR_clear_error();
277			return 1;
278			}
279		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD,
280			ENGINE_R_INVALID_CMD_NAME);
281		return 0;
282		}
283	/* Force the result of the control command to 0 or 1, for the reasons
284	 * mentioned before. */
285        if (ENGINE_ctrl(e, num, i, p, f))
286                return 1;
287        return 0;
288        }
289
290int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
291				int cmd_optional)
292	{
293	int num, flags;
294	long l;
295	char *ptr;
296	if((e == NULL) || (cmd_name == NULL))
297		{
298		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
299			ERR_R_PASSED_NULL_PARAMETER);
300		return 0;
301		}
302	if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e,
303					ENGINE_CTRL_GET_CMD_FROM_NAME,
304					0, (void *)cmd_name, NULL)) <= 0))
305		{
306		/* If the command didn't *have* to be supported, we fake
307		 * success. This allows certain settings to be specified for
308		 * multiple ENGINEs and only require a change of ENGINE id
309		 * (without having to selectively apply settings). Eg. changing
310		 * from a hardware device back to the regular software ENGINE
311		 * without editing the config file, etc. */
312		if(cmd_optional)
313			{
314			ERR_clear_error();
315			return 1;
316			}
317		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
318			ENGINE_R_INVALID_CMD_NAME);
319		return 0;
320		}
321	if(!ENGINE_cmd_is_executable(e, num))
322		{
323		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
324			ENGINE_R_CMD_NOT_EXECUTABLE);
325		return 0;
326		}
327	if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, NULL, NULL)) < 0)
328		{
329		/* Shouldn't happen, given that ENGINE_cmd_is_executable()
330		 * returned success. */
331		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
332			ENGINE_R_INTERNAL_LIST_ERROR);
333		return 0;
334		}
335	/* If the command takes no input, there must be no input. And vice
336	 * versa. */
337	if(flags & ENGINE_CMD_FLAG_NO_INPUT)
338		{
339		if(arg != NULL)
340			{
341			ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
342				ENGINE_R_COMMAND_TAKES_NO_INPUT);
343			return 0;
344			}
345		/* We deliberately force the result of ENGINE_ctrl() to 0 or 1
346		 * rather than returning it as "return data". This is to ensure
347		 * usage of these commands is consistent across applications and
348		 * that certain applications don't understand it one way, and
349		 * others another. */
350		if(ENGINE_ctrl(e, num, 0, (void *)arg, NULL))
351			return 1;
352		return 0;
353		}
354	/* So, we require input */
355	if(arg == NULL)
356		{
357		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
358			ENGINE_R_COMMAND_TAKES_INPUT);
359		return 0;
360		}
361	/* If it takes string input, that's easy */
362	if(flags & ENGINE_CMD_FLAG_STRING)
363		{
364		/* Same explanation as above */
365		if(ENGINE_ctrl(e, num, 0, (void *)arg, NULL))
366			return 1;
367		return 0;
368		}
369	/* If it doesn't take numeric either, then it is unsupported for use in
370	 * a config-setting situation, which is what this function is for. This
371	 * should never happen though, because ENGINE_cmd_is_executable() was
372	 * used. */
373	if(!(flags & ENGINE_CMD_FLAG_NUMERIC))
374		{
375		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
376			ENGINE_R_INTERNAL_LIST_ERROR);
377		return 0;
378		}
379	l = strtol(arg, &ptr, 10);
380	if((arg == ptr) || (*ptr != '\0'))
381		{
382		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
383			ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER);
384		return 0;
385		}
386	/* Force the result of the control command to 0 or 1, for the reasons
387	 * mentioned before. */
388	if(ENGINE_ctrl(e, num, l, NULL, NULL))
389		return 1;
390	return 0;
391	}
392