eng_ctrl.c revision 109998
1181834Sroberto/* crypto/engine/eng_ctrl.c */
2181834Sroberto/* ====================================================================
3290000Sglebius * Copyright (c) 1999-2001 The OpenSSL Project.  All rights reserved.
4181834Sroberto *
5181834Sroberto * Redistribution and use in source and binary forms, with or without
6181834Sroberto * modification, are permitted provided that the following conditions
7290000Sglebius * are met:
8290000Sglebius *
9290000Sglebius * 1. Redistributions of source code must retain the above copyright
10181834Sroberto *    notice, this list of conditions and the following disclaimer.
11181834Sroberto *
12290000Sglebius * 2. Redistributions in binary form must reproduce the above copyright
13290000Sglebius *    notice, this list of conditions and the following disclaimer in
14290000Sglebius *    the documentation and/or other materials provided with the
15181834Sroberto *    distribution.
16290000Sglebius *
17290000Sglebius * 3. All advertising materials mentioning features or use of this
18290000Sglebius *    software must display the following acknowledgment:
19181834Sroberto *    "This product includes software developed by the OpenSSL Project
20290000Sglebius *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
21290000Sglebius *
22181834Sroberto * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23290000Sglebius *    endorse or promote products derived from this software without
24290000Sglebius *    prior written permission. For written permission, please contact
25181834Sroberto *    licensing@OpenSSL.org.
26290000Sglebius *
27181834Sroberto * 5. Products derived from this software may not be called "OpenSSL"
28290000Sglebius *    nor may "OpenSSL" appear in their names without prior written
29290000Sglebius *    permission of the OpenSSL Project.
30290000Sglebius *
31181834Sroberto * 6. Redistributions of any form whatsoever must retain the following
32181834Sroberto *    acknowledgment:
33181834Sroberto *    "This product includes software developed by the OpenSSL Project
34181834Sroberto *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
35290000Sglebius *
36181834Sroberto * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37181834Sroberto * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38181834Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39181834Sroberto * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40181834Sroberto * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41181834Sroberto * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42181834Sroberto * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43181834Sroberto * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44181834Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45181834Sroberto * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46181834Sroberto * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47181834Sroberto * OF THE POSSIBILITY OF SUCH DAMAGE.
48181834Sroberto * ====================================================================
49181834Sroberto *
50181834Sroberto * This product includes cryptographic software written by Eric Young
51181834Sroberto * (eay@cryptsoft.com).  This product includes software written by Tim
52181834Sroberto * Hudson (tjh@cryptsoft.com).
53181834Sroberto *
54181834Sroberto */
55181834Sroberto
56290000Sglebius#include <openssl/crypto.h>
57290000Sglebius#include "cryptlib.h"
58290000Sglebius#include "eng_int.h"
59290000Sglebius#include <openssl/engine.h>
60290000Sglebius
61290000Sglebius/* When querying a ENGINE-specific control command's 'description', this string
62290000Sglebius * is used if the ENGINE_CMD_DEFN has cmd_desc set to NULL. */
63290000Sglebiusstatic const char *int_no_description = "";
64290000Sglebius
65290000Sglebius/* These internal functions handle 'CMD'-related control commands when the
66290000Sglebius * ENGINE in question has asked us to take care of it (ie. the ENGINE did not
67181834Sroberto * set the ENGINE_FLAGS_MANUAL_CMD_CTRL flag. */
68181834Sroberto
69181834Srobertostatic int int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN *defn)
70181834Sroberto	{
71181834Sroberto	if((defn->cmd_num == 0) || (defn->cmd_name == NULL))
72181834Sroberto		return 1;
73290000Sglebius	return 0;
74290000Sglebius	}
75290000Sglebius
76290000Sglebiusstatic int int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN *defn, const char *s)
77290000Sglebius	{
78290000Sglebius	int idx = 0;
79290000Sglebius	while(!int_ctrl_cmd_is_null(defn) && (strcmp(defn->cmd_name, s) != 0))
80290000Sglebius		{
81290000Sglebius		idx++;
82290000Sglebius		defn++;
83290000Sglebius		}
84290000Sglebius	if(int_ctrl_cmd_is_null(defn))
85181834Sroberto		/* The given name wasn't found */
86290000Sglebius		return -1;
87290000Sglebius	return idx;
88290000Sglebius	}
89181834Sroberto
90181834Srobertostatic int int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN *defn, unsigned int num)
91181834Sroberto	{
92290000Sglebius	int idx = 0;
93290000Sglebius	/* NB: It is stipulated that 'cmd_defn' lists are ordered by cmd_num. So
94290000Sglebius	 * our searches don't need to take any longer than necessary. */
95181834Sroberto	while(!int_ctrl_cmd_is_null(defn) && (defn->cmd_num < num))
96181834Sroberto		{
97290000Sglebius		idx++;
98290000Sglebius		defn++;
99290000Sglebius		}
100290000Sglebius	if(defn->cmd_num == num)
101290000Sglebius		return idx;
102181834Sroberto	/* The given cmd_num wasn't found */
103181834Sroberto	return -1;
104290000Sglebius	}
105290000Sglebius
106290000Sglebiusstatic int int_ctrl_helper(ENGINE *e, int cmd, long i, void *p, void (*f)())
107290000Sglebius	{
108290000Sglebius	int idx;
109290000Sglebius	char *s = (char *)p;
110290000Sglebius	/* Take care of the easy one first (eg. it requires no searches) */
111290000Sglebius	if(cmd == ENGINE_CTRL_GET_FIRST_CMD_TYPE)
112290000Sglebius		{
113290000Sglebius		if((e->cmd_defns == NULL) || int_ctrl_cmd_is_null(e->cmd_defns))
114290000Sglebius			return 0;
115290000Sglebius		return e->cmd_defns->cmd_num;
116290000Sglebius		}
117290000Sglebius	/* One or two commands require that "p" be a valid string buffer */
118290000Sglebius	if((cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) ||
119290000Sglebius			(cmd == ENGINE_CTRL_GET_NAME_FROM_CMD) ||
120290000Sglebius			(cmd == ENGINE_CTRL_GET_DESC_FROM_CMD))
121290000Sglebius		{
122181834Sroberto		if(s == NULL)
123181834Sroberto			{
124181834Sroberto			ENGINEerr(ENGINE_F_INT_CTRL_HELPER,
125181834Sroberto				ERR_R_PASSED_NULL_PARAMETER);
126181834Sroberto			return -1;
127181834Sroberto			}
128181834Sroberto		}
129181834Sroberto	/* Now handle cmd_name -> cmd_num conversion */
130290000Sglebius	if(cmd == ENGINE_CTRL_GET_CMD_FROM_NAME)
131181834Sroberto		{
132181834Sroberto		if((e->cmd_defns == NULL) || ((idx = int_ctrl_cmd_by_name(
133290000Sglebius						e->cmd_defns, s)) < 0))
134290000Sglebius			{
135290000Sglebius			ENGINEerr(ENGINE_F_INT_CTRL_HELPER,
136290000Sglebius				ENGINE_R_INVALID_CMD_NAME);
137181834Sroberto			return -1;
138290000Sglebius			}
139290000Sglebius		return e->cmd_defns[idx].cmd_num;
140290000Sglebius		}
141290000Sglebius	/* For the rest of the commands, the 'long' argument must specify a
142181834Sroberto	 * valie command number - so we need to conduct a search. */
143290000Sglebius	if((e->cmd_defns == NULL) || ((idx = int_ctrl_cmd_by_num(e->cmd_defns,
144290000Sglebius					(unsigned int)i)) < 0))
145290000Sglebius		{
146181834Sroberto		ENGINEerr(ENGINE_F_INT_CTRL_HELPER,
147181834Sroberto			ENGINE_R_INVALID_CMD_NUMBER);
148181834Sroberto		return -1;
149181834Sroberto		}
150290000Sglebius	/* Now the logic splits depending on command type */
151181834Sroberto	switch(cmd)
152290000Sglebius		{
153181834Sroberto	case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
154290000Sglebius		idx++;
155181834Sroberto		if(int_ctrl_cmd_is_null(e->cmd_defns + idx))
156181834Sroberto			/* end-of-list */
157290000Sglebius			return 0;
158290000Sglebius		else
159290000Sglebius			return e->cmd_defns[idx].cmd_num;
160290000Sglebius	case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
161290000Sglebius		return strlen(e->cmd_defns[idx].cmd_name);
162290000Sglebius	case ENGINE_CTRL_GET_NAME_FROM_CMD:
163290000Sglebius		return sprintf(s, "%s", e->cmd_defns[idx].cmd_name);
164290000Sglebius	case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
165290000Sglebius		if(e->cmd_defns[idx].cmd_desc)
166181834Sroberto			return strlen(e->cmd_defns[idx].cmd_desc);
167290000Sglebius		return strlen(int_no_description);
168290000Sglebius	case ENGINE_CTRL_GET_DESC_FROM_CMD:
169290000Sglebius		if(e->cmd_defns[idx].cmd_desc)
170290000Sglebius			return sprintf(s, "%s", e->cmd_defns[idx].cmd_desc);
171290000Sglebius		return sprintf(s, "%s", int_no_description);
172181834Sroberto	case ENGINE_CTRL_GET_CMD_FLAGS:
173290000Sglebius		return e->cmd_defns[idx].cmd_flags;
174290000Sglebius		}
175290000Sglebius	/* Shouldn't really be here ... */
176290000Sglebius	ENGINEerr(ENGINE_F_INT_CTRL_HELPER,ENGINE_R_INTERNAL_LIST_ERROR);
177181834Sroberto	return -1;
178181834Sroberto	}
179181834Sroberto
180290000Sglebiusint ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)())
181181834Sroberto	{
182290000Sglebius	int ctrl_exists, ref_exists;
183181834Sroberto	if(e == NULL)
184181834Sroberto		{
185181834Sroberto		ENGINEerr(ENGINE_F_ENGINE_CTRL,ERR_R_PASSED_NULL_PARAMETER);
186181834Sroberto		return 0;
187181834Sroberto		}
188181834Sroberto	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
189181834Sroberto	ref_exists = ((e->struct_ref > 0) ? 1 : 0);
190181834Sroberto	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
191290000Sglebius	ctrl_exists = ((e->ctrl == NULL) ? 0 : 1);
192290000Sglebius	if(!ref_exists)
193290000Sglebius		{
194290000Sglebius		ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_REFERENCE);
195290000Sglebius		return 0;
196181834Sroberto		}
197290000Sglebius	/* Intercept any "root-level" commands before trying to hand them on to
198290000Sglebius	 * ctrl() handlers. */
199290000Sglebius	switch(cmd)
200290000Sglebius		{
201181834Sroberto	case ENGINE_CTRL_HAS_CTRL_FUNCTION:
202181834Sroberto		return ctrl_exists;
203181834Sroberto	case ENGINE_CTRL_GET_FIRST_CMD_TYPE:
204181834Sroberto	case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
205181834Sroberto	case ENGINE_CTRL_GET_CMD_FROM_NAME:
206181834Sroberto	case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
207181834Sroberto	case ENGINE_CTRL_GET_NAME_FROM_CMD:
208181834Sroberto	case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
209181834Sroberto	case ENGINE_CTRL_GET_DESC_FROM_CMD:
210181834Sroberto	case ENGINE_CTRL_GET_CMD_FLAGS:
211181834Sroberto		if(ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL))
212181834Sroberto			return int_ctrl_helper(e,cmd,i,p,f);
213181834Sroberto		if(!ctrl_exists)
214181834Sroberto			{
215181834Sroberto			ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_CONTROL_FUNCTION);
216181834Sroberto			/* For these cmd-related functions, failure is indicated
217181834Sroberto			 * by a -1 return value (because 0 is used as a valid
218290000Sglebius			 * return in some places). */
219290000Sglebius			return -1;
220290000Sglebius			}
221290000Sglebius	default:
222181834Sroberto		break;
223181834Sroberto		}
224181834Sroberto	/* Anything else requires a ctrl() handler to exist. */
225181834Sroberto	if(!ctrl_exists)
226181834Sroberto		{
227290000Sglebius		ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_CONTROL_FUNCTION);
228290000Sglebius		return 0;
229290000Sglebius		}
230181834Sroberto	return e->ctrl(e, cmd, i, p, f);
231181834Sroberto	}
232181834Sroberto
233181834Srobertoint ENGINE_cmd_is_executable(ENGINE *e, int cmd)
234181834Sroberto	{
235181834Sroberto	int flags;
236181834Sroberto	if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, NULL, NULL)) < 0)
237290000Sglebius		{
238290000Sglebius		ENGINEerr(ENGINE_F_ENGINE_CMD_IS_EXECUTABLE,
239290000Sglebius			ENGINE_R_INVALID_CMD_NUMBER);
240290000Sglebius		return 0;
241181834Sroberto		}
242290000Sglebius	if(!(flags & ENGINE_CMD_FLAG_NO_INPUT) &&
243290000Sglebius			!(flags & ENGINE_CMD_FLAG_NUMERIC) &&
244290000Sglebius			!(flags & ENGINE_CMD_FLAG_STRING))
245290000Sglebius		return 0;
246290000Sglebius	return 1;
247290000Sglebius	}
248290000Sglebius
249290000Sglebiusint ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
250290000Sglebius        long i, void *p, void (*f)(), int cmd_optional)
251290000Sglebius        {
252290000Sglebius	int num;
253290000Sglebius
254290000Sglebius	if((e == NULL) || (cmd_name == NULL))
255290000Sglebius		{
256290000Sglebius		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
257181834Sroberto			ERR_R_PASSED_NULL_PARAMETER);
258181834Sroberto		return 0;
259290000Sglebius		}
260290000Sglebius	if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e,
261290000Sglebius					ENGINE_CTRL_GET_CMD_FROM_NAME,
262290000Sglebius					0, (void *)cmd_name, NULL)) <= 0))
263181834Sroberto		{
264181834Sroberto		/* If the command didn't *have* to be supported, we fake
265290000Sglebius		 * success. This allows certain settings to be specified for
266181834Sroberto		 * multiple ENGINEs and only require a change of ENGINE id
267181834Sroberto		 * (without having to selectively apply settings). Eg. changing
268290000Sglebius		 * from a hardware device back to the regular software ENGINE
269181834Sroberto		 * without editing the config file, etc. */
270290000Sglebius		if(cmd_optional)
271181834Sroberto			{
272181834Sroberto			ERR_clear_error();
273290000Sglebius			return 1;
274181834Sroberto			}
275290000Sglebius		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD,
276181834Sroberto			ENGINE_R_INVALID_CMD_NAME);
277181834Sroberto		return 0;
278181834Sroberto		}
279181834Sroberto	/* Force the result of the control command to 0 or 1, for the reasons
280181834Sroberto	 * mentioned before. */
281181834Sroberto        if (ENGINE_ctrl(e, num, i, p, f))
282181834Sroberto                return 1;
283181834Sroberto        return 0;
284181834Sroberto        }
285181834Sroberto
286181834Srobertoint ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
287181834Sroberto				int cmd_optional)
288181834Sroberto	{
289181834Sroberto	int num, flags;
290181834Sroberto	long l;
291181834Sroberto	char *ptr;
292181834Sroberto	if((e == NULL) || (cmd_name == NULL))
293181834Sroberto		{
294181834Sroberto		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
295181834Sroberto			ERR_R_PASSED_NULL_PARAMETER);
296181834Sroberto		return 0;
297181834Sroberto		}
298181834Sroberto	if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e,
299181834Sroberto					ENGINE_CTRL_GET_CMD_FROM_NAME,
300181834Sroberto					0, (void *)cmd_name, NULL)) <= 0))
301181834Sroberto		{
302181834Sroberto		/* If the command didn't *have* to be supported, we fake
303181834Sroberto		 * success. This allows certain settings to be specified for
304181834Sroberto		 * multiple ENGINEs and only require a change of ENGINE id
305290000Sglebius		 * (without having to selectively apply settings). Eg. changing
306290000Sglebius		 * from a hardware device back to the regular software ENGINE
307181834Sroberto		 * without editing the config file, etc. */
308181834Sroberto		if(cmd_optional)
309181834Sroberto			{
310181834Sroberto			ERR_clear_error();
311181834Sroberto			return 1;
312181834Sroberto			}
313181834Sroberto		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
314181834Sroberto			ENGINE_R_INVALID_CMD_NAME);
315181834Sroberto		return 0;
316181834Sroberto		}
317181834Sroberto	if(!ENGINE_cmd_is_executable(e, num))
318181834Sroberto		{
319181834Sroberto		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
320181834Sroberto			ENGINE_R_CMD_NOT_EXECUTABLE);
321181834Sroberto		return 0;
322181834Sroberto		}
323181834Sroberto	if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, NULL, NULL)) < 0)
324181834Sroberto		{
325181834Sroberto		/* Shouldn't happen, given that ENGINE_cmd_is_executable()
326181834Sroberto		 * returned success. */
327290000Sglebius		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
328290000Sglebius			ENGINE_R_INTERNAL_LIST_ERROR);
329181834Sroberto		return 0;
330181834Sroberto		}
331181834Sroberto	/* If the command takes no input, there must be no input. And vice
332181834Sroberto	 * versa. */
333181834Sroberto	if(flags & ENGINE_CMD_FLAG_NO_INPUT)
334181834Sroberto		{
335181834Sroberto		if(arg != NULL)
336181834Sroberto			{
337181834Sroberto			ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
338181834Sroberto				ENGINE_R_COMMAND_TAKES_NO_INPUT);
339181834Sroberto			return 0;
340181834Sroberto			}
341181834Sroberto		/* We deliberately force the result of ENGINE_ctrl() to 0 or 1
342181834Sroberto		 * rather than returning it as "return data". This is to ensure
343181834Sroberto		 * usage of these commands is consistent across applications and
344181834Sroberto		 * that certain applications don't understand it one way, and
345181834Sroberto		 * others another. */
346181834Sroberto		if(ENGINE_ctrl(e, num, 0, (void *)arg, NULL))
347181834Sroberto			return 1;
348181834Sroberto		return 0;
349181834Sroberto		}
350181834Sroberto	/* So, we require input */
351181834Sroberto	if(arg == NULL)
352181834Sroberto		{
353181834Sroberto		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
354181834Sroberto			ENGINE_R_COMMAND_TAKES_INPUT);
355181834Sroberto		return 0;
356181834Sroberto		}
357181834Sroberto	/* If it takes string input, that's easy */
358181834Sroberto	if(flags & ENGINE_CMD_FLAG_STRING)
359181834Sroberto		{
360181834Sroberto		/* Same explanation as above */
361181834Sroberto		if(ENGINE_ctrl(e, num, 0, (void *)arg, NULL))
362181834Sroberto			return 1;
363181834Sroberto		return 0;
364181834Sroberto		}
365181834Sroberto	/* If it doesn't take numeric either, then it is unsupported for use in
366181834Sroberto	 * a config-setting situation, which is what this function is for. This
367181834Sroberto	 * should never happen though, because ENGINE_cmd_is_executable() was
368181834Sroberto	 * used. */
369181834Sroberto	if(!(flags & ENGINE_CMD_FLAG_NUMERIC))
370181834Sroberto		{
371181834Sroberto		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
372290000Sglebius			ENGINE_R_INTERNAL_LIST_ERROR);
373181834Sroberto		return 0;
374181834Sroberto		}
375181834Sroberto	l = strtol(arg, &ptr, 10);
376181834Sroberto	if((arg == ptr) || (*ptr != '\0'))
377181834Sroberto		{
378181834Sroberto		ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING,
379181834Sroberto			ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER);
380181834Sroberto		return 0;
381181834Sroberto		}
382290000Sglebius	/* Force the result of the control command to 0 or 1, for the reasons
383290000Sglebius	 * mentioned before. */
384181834Sroberto	if(ENGINE_ctrl(e, num, l, NULL, NULL))
385181834Sroberto		return 1;
386290000Sglebius	return 0;
387290000Sglebius	}
388290000Sglebius