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