1 /*
2 * Copyright 2001-2023 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 /* We need to use some engine deprecated APIs */
11 #define OPENSSL_SUPPRESS_DEPRECATED
12
13 #include "eng_local.h"
14
15 /*
16 * When querying a ENGINE-specific control command's 'description', this
17 * string is used if the ENGINE_CMD_DEFN has cmd_desc set to NULL.
18 */
19 static const char *int_no_description = "";
20
21 /*
22 * These internal functions handle 'CMD'-related control commands when the
23 * ENGINE in question has asked us to take care of it (ie. the ENGINE did not
24 * set the ENGINE_FLAGS_MANUAL_CMD_CTRL flag.
25 */
26
int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN * defn)27 static int int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN *defn)
28 {
29 if ((defn->cmd_num == 0) || (defn->cmd_name == NULL))
30 return 1;
31 return 0;
32 }
33
int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN * defn,const char * s)34 static int int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN *defn, const char *s)
35 {
36 int idx = 0;
37 while (!int_ctrl_cmd_is_null(defn) && (strcmp(defn->cmd_name, s) != 0)) {
38 idx++;
39 defn++;
40 }
41 if (int_ctrl_cmd_is_null(defn))
42 /* The given name wasn't found */
43 return -1;
44 return idx;
45 }
46
int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN * defn,unsigned int num)47 static int int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN *defn, unsigned int num)
48 {
49 int idx = 0;
50 /*
51 * NB: It is stipulated that 'cmd_defn' lists are ordered by cmd_num. So
52 * our searches don't need to take any longer than necessary.
53 */
54 while (!int_ctrl_cmd_is_null(defn) && (defn->cmd_num < num)) {
55 idx++;
56 defn++;
57 }
58 if (defn->cmd_num == num)
59 return idx;
60 /* The given cmd_num wasn't found */
61 return -1;
62 }
63
int_ctrl_helper(ENGINE * e,int cmd,long i,void * p,void (* f)(void))64 static int int_ctrl_helper(ENGINE *e, int cmd, long i, void *p,
65 void (*f)(void))
66 {
67 int idx;
68 char *s = (char *)p;
69 const ENGINE_CMD_DEFN *cdp;
70
71 /* Take care of the easy one first (eg. it requires no searches) */
72 if (cmd == ENGINE_CTRL_GET_FIRST_CMD_TYPE) {
73 if ((e->cmd_defns == NULL) || int_ctrl_cmd_is_null(e->cmd_defns))
74 return 0;
75 return e->cmd_defns->cmd_num;
76 }
77 /* One or two commands require that "p" be a valid string buffer */
78 if ((cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) || (cmd == ENGINE_CTRL_GET_NAME_FROM_CMD) || (cmd == ENGINE_CTRL_GET_DESC_FROM_CMD)) {
79 if (s == NULL) {
80 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
81 return -1;
82 }
83 }
84 /* Now handle cmd_name -> cmd_num conversion */
85 if (cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) {
86 if ((e->cmd_defns == NULL)
87 || ((idx = int_ctrl_cmd_by_name(e->cmd_defns, s)) < 0)) {
88 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NAME);
89 return -1;
90 }
91 return e->cmd_defns[idx].cmd_num;
92 }
93 /*
94 * For the rest of the commands, the 'long' argument must specify a valid
95 * command number - so we need to conduct a search.
96 */
97 if ((e->cmd_defns == NULL)
98 || ((idx = int_ctrl_cmd_by_num(e->cmd_defns, (unsigned int)i)) < 0)) {
99 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NUMBER);
100 return -1;
101 }
102 /* Now the logic splits depending on command type */
103 cdp = &e->cmd_defns[idx];
104 switch (cmd) {
105 case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
106 cdp++;
107 return int_ctrl_cmd_is_null(cdp) ? 0 : cdp->cmd_num;
108 case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
109 return strlen(cdp->cmd_name);
110 case ENGINE_CTRL_GET_NAME_FROM_CMD:
111 return strlen(strcpy(s, cdp->cmd_name));
112 case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
113 return strlen(cdp->cmd_desc == NULL ? int_no_description
114 : cdp->cmd_desc);
115 case ENGINE_CTRL_GET_DESC_FROM_CMD:
116 return strlen(strcpy(s, cdp->cmd_desc == NULL ? int_no_description : cdp->cmd_desc));
117 case ENGINE_CTRL_GET_CMD_FLAGS:
118 return cdp->cmd_flags;
119 }
120 /* Shouldn't really be here ... */
121 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
122 return -1;
123 }
124
ENGINE_ctrl(ENGINE * e,int cmd,long i,void * p,void (* f)(void))125 int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void))
126 {
127 int ctrl_exists;
128
129 if (e == NULL) {
130 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
131 return 0;
132 }
133
134 ctrl_exists = ((e->ctrl == NULL) ? 0 : 1);
135
136 /*
137 * Intercept any "root-level" commands before trying to hand them on to
138 * ctrl() handlers.
139 */
140 switch (cmd) {
141 case ENGINE_CTRL_HAS_CTRL_FUNCTION:
142 return ctrl_exists;
143 case ENGINE_CTRL_GET_FIRST_CMD_TYPE:
144 case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
145 case ENGINE_CTRL_GET_CMD_FROM_NAME:
146 case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
147 case ENGINE_CTRL_GET_NAME_FROM_CMD:
148 case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
149 case ENGINE_CTRL_GET_DESC_FROM_CMD:
150 case ENGINE_CTRL_GET_CMD_FLAGS:
151 if (ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL))
152 return int_ctrl_helper(e, cmd, i, p, f);
153 if (!ctrl_exists) {
154 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_NO_CONTROL_FUNCTION);
155 /*
156 * For these cmd-related functions, failure is indicated by a -1
157 * return value (because 0 is used as a valid return in some
158 * places).
159 */
160 return -1;
161 }
162 default:
163 break;
164 }
165 /* Anything else requires a ctrl() handler to exist. */
166 if (!ctrl_exists) {
167 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_NO_CONTROL_FUNCTION);
168 return 0;
169 }
170 return e->ctrl(e, cmd, i, p, f);
171 }
172
ENGINE_cmd_is_executable(ENGINE * e,int cmd)173 int ENGINE_cmd_is_executable(ENGINE *e, int cmd)
174 {
175 int flags;
176 if ((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, NULL, NULL)) < 0) {
177 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NUMBER);
178 return 0;
179 }
180 if (!(flags & ENGINE_CMD_FLAG_NO_INPUT) && !(flags & ENGINE_CMD_FLAG_NUMERIC) && !(flags & ENGINE_CMD_FLAG_STRING))
181 return 0;
182 return 1;
183 }
184
ENGINE_ctrl_cmd(ENGINE * e,const char * cmd_name,long i,void * p,void (* f)(void),int cmd_optional)185 int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
186 long i, void *p, void (*f)(void), int cmd_optional)
187 {
188 int num;
189
190 if (e == NULL || cmd_name == NULL) {
191 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
192 return 0;
193 }
194 if (e->ctrl == NULL
195 || (num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME,
196 0, (void *)cmd_name, NULL))
197 <= 0) {
198 /*
199 * If the command didn't *have* to be supported, we fake success.
200 * This allows certain settings to be specified for multiple ENGINEs
201 * and only require a change of ENGINE id (without having to
202 * selectively apply settings). Eg. changing from a hardware device
203 * back to the regular software ENGINE without editing the config
204 * file, etc.
205 */
206 if (cmd_optional) {
207 ERR_clear_error();
208 return 1;
209 }
210 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NAME);
211 return 0;
212 }
213 /*
214 * Force the result of the control command to 0 or 1, for the reasons
215 * mentioned before.
216 */
217 if (ENGINE_ctrl(e, num, i, p, f) > 0)
218 return 1;
219 return 0;
220 }
221
ENGINE_ctrl_cmd_string(ENGINE * e,const char * cmd_name,const char * arg,int cmd_optional)222 int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
223 int cmd_optional)
224 {
225 int num, flags;
226 long l;
227 char *ptr;
228
229 if (e == NULL || cmd_name == NULL) {
230 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
231 return 0;
232 }
233 if (e->ctrl == NULL
234 || (num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME,
235 0, (void *)cmd_name, NULL))
236 <= 0) {
237 /*
238 * If the command didn't *have* to be supported, we fake success.
239 * This allows certain settings to be specified for multiple ENGINEs
240 * and only require a change of ENGINE id (without having to
241 * selectively apply settings). Eg. changing from a hardware device
242 * back to the regular software ENGINE without editing the config
243 * file, etc.
244 */
245 if (cmd_optional) {
246 ERR_clear_error();
247 return 1;
248 }
249 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NAME);
250 return 0;
251 }
252 if (!ENGINE_cmd_is_executable(e, num)) {
253 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_CMD_NOT_EXECUTABLE);
254 return 0;
255 }
256
257 flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, NULL, NULL);
258 if (flags < 0) {
259 /*
260 * Shouldn't happen, given that ENGINE_cmd_is_executable() returned
261 * success.
262 */
263 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
264 return 0;
265 }
266 /*
267 * If the command takes no input, there must be no input. And vice versa.
268 */
269 if (flags & ENGINE_CMD_FLAG_NO_INPUT) {
270 if (arg != NULL) {
271 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_COMMAND_TAKES_NO_INPUT);
272 return 0;
273 }
274 /*
275 * We deliberately force the result of ENGINE_ctrl() to 0 or 1 rather
276 * than returning it as "return data". This is to ensure usage of
277 * these commands is consistent across applications and that certain
278 * applications don't understand it one way, and others another.
279 */
280 if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0)
281 return 1;
282 return 0;
283 }
284 /* So, we require input */
285 if (arg == NULL) {
286 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_COMMAND_TAKES_INPUT);
287 return 0;
288 }
289 /* If it takes string input, that's easy */
290 if (flags & ENGINE_CMD_FLAG_STRING) {
291 /* Same explanation as above */
292 if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0)
293 return 1;
294 return 0;
295 }
296 /*
297 * If it doesn't take numeric either, then it is unsupported for use in a
298 * config-setting situation, which is what this function is for. This
299 * should never happen though, because ENGINE_cmd_is_executable() was
300 * used.
301 */
302 if (!(flags & ENGINE_CMD_FLAG_NUMERIC)) {
303 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
304 return 0;
305 }
306 l = strtol(arg, &ptr, 10);
307 if ((arg == ptr) || (*ptr != '\0')) {
308 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER);
309 return 0;
310 }
311 /*
312 * Force the result of the control command to 0 or 1, for the reasons
313 * mentioned before.
314 */
315 if (ENGINE_ctrl(e, num, l, NULL, NULL) > 0)
316 return 1;
317 return 0;
318 }
319