]> git.ipfire.org Git - thirdparty/openssl.git/blob - crypto/engine/eng_ctrl.c
2dc798c1a360e6ab2211d0aeb655f53ebd83686a
[thirdparty/openssl.git] / crypto / engine / eng_ctrl.c
1 /*
2 * Copyright 2001-2020 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
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
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
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
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) ||
79 (cmd == ENGINE_CTRL_GET_NAME_FROM_CMD) ||
80 (cmd == ENGINE_CTRL_GET_DESC_FROM_CMD)) {
81 if (s == NULL) {
82 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
83 return -1;
84 }
85 }
86 /* Now handle cmd_name -> cmd_num conversion */
87 if (cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) {
88 if ((e->cmd_defns == NULL)
89 || ((idx = int_ctrl_cmd_by_name(e->cmd_defns, s)) < 0)) {
90 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NAME);
91 return -1;
92 }
93 return e->cmd_defns[idx].cmd_num;
94 }
95 /*
96 * For the rest of the commands, the 'long' argument must specify a valid
97 * command number - so we need to conduct a search.
98 */
99 if ((e->cmd_defns == NULL)
100 || ((idx = int_ctrl_cmd_by_num(e->cmd_defns, (unsigned int)i)) < 0)) {
101 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NUMBER);
102 return -1;
103 }
104 /* Now the logic splits depending on command type */
105 cdp = &e->cmd_defns[idx];
106 switch (cmd) {
107 case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
108 cdp++;
109 return int_ctrl_cmd_is_null(cdp) ? 0 : cdp->cmd_num;
110 case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
111 return strlen(cdp->cmd_name);
112 case ENGINE_CTRL_GET_NAME_FROM_CMD:
113 return strlen(strcpy(s, cdp->cmd_name));
114 case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
115 return strlen(cdp->cmd_desc == NULL ? int_no_description
116 : cdp->cmd_desc);
117 case ENGINE_CTRL_GET_DESC_FROM_CMD:
118 return strlen(strcpy(s, cdp->cmd_desc == NULL ? int_no_description
119 : cdp->cmd_desc));
120 case ENGINE_CTRL_GET_CMD_FLAGS:
121 return cdp->cmd_flags;
122 }
123 /* Shouldn't really be here ... */
124 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
125 return -1;
126 }
127
128 int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
129 {
130 int ctrl_exists, ref_exists;
131 if (e == NULL) {
132 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
133 return 0;
134 }
135 if (!CRYPTO_THREAD_write_lock(global_engine_lock))
136 return 0;
137 ref_exists = ((e->struct_ref > 0) ? 1 : 0);
138 CRYPTO_THREAD_unlock(global_engine_lock);
139 ctrl_exists = ((e->ctrl == NULL) ? 0 : 1);
140 if (!ref_exists) {
141 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_NO_REFERENCE);
142 return 0;
143 }
144 /*
145 * Intercept any "root-level" commands before trying to hand them on to
146 * ctrl() handlers.
147 */
148 switch (cmd) {
149 case ENGINE_CTRL_HAS_CTRL_FUNCTION:
150 return ctrl_exists;
151 case ENGINE_CTRL_GET_FIRST_CMD_TYPE:
152 case ENGINE_CTRL_GET_NEXT_CMD_TYPE:
153 case ENGINE_CTRL_GET_CMD_FROM_NAME:
154 case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD:
155 case ENGINE_CTRL_GET_NAME_FROM_CMD:
156 case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD:
157 case ENGINE_CTRL_GET_DESC_FROM_CMD:
158 case ENGINE_CTRL_GET_CMD_FLAGS:
159 if (ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL))
160 return int_ctrl_helper(e, cmd, i, p, f);
161 if (!ctrl_exists) {
162 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_NO_CONTROL_FUNCTION);
163 /*
164 * For these cmd-related functions, failure is indicated by a -1
165 * return value (because 0 is used as a valid return in some
166 * places).
167 */
168 return -1;
169 }
170 default:
171 break;
172 }
173 /* Anything else requires a ctrl() handler to exist. */
174 if (!ctrl_exists) {
175 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_NO_CONTROL_FUNCTION);
176 return 0;
177 }
178 return e->ctrl(e, cmd, i, p, f);
179 }
180
181 int ENGINE_cmd_is_executable(ENGINE *e, int cmd)
182 {
183 int flags;
184 if ((flags =
185 ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, NULL, NULL)) < 0) {
186 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NUMBER);
187 return 0;
188 }
189 if (!(flags & ENGINE_CMD_FLAG_NO_INPUT) &&
190 !(flags & ENGINE_CMD_FLAG_NUMERIC) &&
191 !(flags & ENGINE_CMD_FLAG_STRING))
192 return 0;
193 return 1;
194 }
195
196 int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
197 long i, void *p, void (*f) (void), int cmd_optional)
198 {
199 int num;
200
201 if (e == NULL || cmd_name == NULL) {
202 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
203 return 0;
204 }
205 if (e->ctrl == NULL
206 || (num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME,
207 0, (void *)cmd_name, NULL)) <= 0) {
208 /*
209 * If the command didn't *have* to be supported, we fake success.
210 * This allows certain settings to be specified for multiple ENGINEs
211 * and only require a change of ENGINE id (without having to
212 * selectively apply settings). Eg. changing from a hardware device
213 * back to the regular software ENGINE without editing the config
214 * file, etc.
215 */
216 if (cmd_optional) {
217 ERR_clear_error();
218 return 1;
219 }
220 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NAME);
221 return 0;
222 }
223 /*
224 * Force the result of the control command to 0 or 1, for the reasons
225 * mentioned before.
226 */
227 if (ENGINE_ctrl(e, num, i, p, f) > 0)
228 return 1;
229 return 0;
230 }
231
232 int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
233 int cmd_optional)
234 {
235 int num, flags;
236 long l;
237 char *ptr;
238
239 if (e == NULL || cmd_name == NULL) {
240 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER);
241 return 0;
242 }
243 if (e->ctrl == NULL
244 || (num = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FROM_NAME,
245 0, (void *)cmd_name, NULL)) <= 0) {
246 /*
247 * If the command didn't *have* to be supported, we fake success.
248 * This allows certain settings to be specified for multiple ENGINEs
249 * and only require a change of ENGINE id (without having to
250 * selectively apply settings). Eg. changing from a hardware device
251 * back to the regular software ENGINE without editing the config
252 * file, etc.
253 */
254 if (cmd_optional) {
255 ERR_clear_error();
256 return 1;
257 }
258 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INVALID_CMD_NAME);
259 return 0;
260 }
261 if (!ENGINE_cmd_is_executable(e, num)) {
262 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_CMD_NOT_EXECUTABLE);
263 return 0;
264 }
265
266 flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, NULL, NULL);
267 if (flags < 0) {
268 /*
269 * Shouldn't happen, given that ENGINE_cmd_is_executable() returned
270 * success.
271 */
272 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
273 return 0;
274 }
275 /*
276 * If the command takes no input, there must be no input. And vice versa.
277 */
278 if (flags & ENGINE_CMD_FLAG_NO_INPUT) {
279 if (arg != NULL) {
280 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_COMMAND_TAKES_NO_INPUT);
281 return 0;
282 }
283 /*
284 * We deliberately force the result of ENGINE_ctrl() to 0 or 1 rather
285 * than returning it as "return data". This is to ensure usage of
286 * these commands is consistent across applications and that certain
287 * applications don't understand it one way, and others another.
288 */
289 if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0)
290 return 1;
291 return 0;
292 }
293 /* So, we require input */
294 if (arg == NULL) {
295 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_COMMAND_TAKES_INPUT);
296 return 0;
297 }
298 /* If it takes string input, that's easy */
299 if (flags & ENGINE_CMD_FLAG_STRING) {
300 /* Same explanation as above */
301 if (ENGINE_ctrl(e, num, 0, (void *)arg, NULL) > 0)
302 return 1;
303 return 0;
304 }
305 /*
306 * If it doesn't take numeric either, then it is unsupported for use in a
307 * config-setting situation, which is what this function is for. This
308 * should never happen though, because ENGINE_cmd_is_executable() was
309 * used.
310 */
311 if (!(flags & ENGINE_CMD_FLAG_NUMERIC)) {
312 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR);
313 return 0;
314 }
315 l = strtol(arg, &ptr, 10);
316 if ((arg == ptr) || (*ptr != '\0')) {
317 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER);
318 return 0;
319 }
320 /*
321 * Force the result of the control command to 0 or 1, for the reasons
322 * mentioned before.
323 */
324 if (ENGINE_ctrl(e, num, l, NULL, NULL) > 0)
325 return 1;
326 return 0;
327 }