2 * Copyright 2001-2020 The OpenSSL Project Authors. All Rights Reserved.
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
10 /* We need to use some engine deprecated APIs */
11 #define OPENSSL_SUPPRESS_DEPRECATED
13 #include "eng_local.h"
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.
19 static const char *int_no_description
= "";
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.
27 static int int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN
*defn
)
29 if ((defn
->cmd_num
== 0) || (defn
->cmd_name
== NULL
))
34 static int int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN
*defn
, const char *s
)
37 while (!int_ctrl_cmd_is_null(defn
) && (strcmp(defn
->cmd_name
, s
) != 0)) {
41 if (int_ctrl_cmd_is_null(defn
))
42 /* The given name wasn't found */
47 static int int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN
*defn
, unsigned int num
)
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.
54 while (!int_ctrl_cmd_is_null(defn
) && (defn
->cmd_num
< num
)) {
58 if (defn
->cmd_num
== num
)
60 /* The given cmd_num wasn't found */
64 static int int_ctrl_helper(ENGINE
*e
, int cmd
, long i
, void *p
,
69 const ENGINE_CMD_DEFN
*cdp
;
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
))
75 return e
->cmd_defns
->cmd_num
;
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
)) {
82 ERR_raise(ERR_LIB_ENGINE
, ERR_R_PASSED_NULL_PARAMETER
);
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
);
93 return e
->cmd_defns
[idx
].cmd_num
;
96 * For the rest of the commands, the 'long' argument must specify a valid
97 * command number - so we need to conduct a search.
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
);
104 /* Now the logic splits depending on command type */
105 cdp
= &e
->cmd_defns
[idx
];
107 case ENGINE_CTRL_GET_NEXT_CMD_TYPE
:
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
117 case ENGINE_CTRL_GET_DESC_FROM_CMD
:
118 return strlen(strcpy(s
, cdp
->cmd_desc
== NULL
? int_no_description
120 case ENGINE_CTRL_GET_CMD_FLAGS
:
121 return cdp
->cmd_flags
;
123 /* Shouldn't really be here ... */
124 ERR_raise(ERR_LIB_ENGINE
, ENGINE_R_INTERNAL_LIST_ERROR
);
128 int ENGINE_ctrl(ENGINE
*e
, int cmd
, long i
, void *p
, void (*f
) (void))
130 int ctrl_exists
, ref_exists
;
132 ERR_raise(ERR_LIB_ENGINE
, ERR_R_PASSED_NULL_PARAMETER
);
135 if (!CRYPTO_THREAD_write_lock(global_engine_lock
))
137 ref_exists
= ((e
->struct_ref
> 0) ? 1 : 0);
138 CRYPTO_THREAD_unlock(global_engine_lock
);
139 ctrl_exists
= ((e
->ctrl
== NULL
) ? 0 : 1);
141 ERR_raise(ERR_LIB_ENGINE
, ENGINE_R_NO_REFERENCE
);
145 * Intercept any "root-level" commands before trying to hand them on to
149 case ENGINE_CTRL_HAS_CTRL_FUNCTION
:
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
);
162 ERR_raise(ERR_LIB_ENGINE
, ENGINE_R_NO_CONTROL_FUNCTION
);
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
173 /* Anything else requires a ctrl() handler to exist. */
175 ERR_raise(ERR_LIB_ENGINE
, ENGINE_R_NO_CONTROL_FUNCTION
);
178 return e
->ctrl(e
, cmd
, i
, p
, f
);
181 int ENGINE_cmd_is_executable(ENGINE
*e
, int cmd
)
185 ENGINE_ctrl(e
, ENGINE_CTRL_GET_CMD_FLAGS
, cmd
, NULL
, NULL
)) < 0) {
186 ERR_raise(ERR_LIB_ENGINE
, ENGINE_R_INVALID_CMD_NUMBER
);
189 if (!(flags
& ENGINE_CMD_FLAG_NO_INPUT
) &&
190 !(flags
& ENGINE_CMD_FLAG_NUMERIC
) &&
191 !(flags
& ENGINE_CMD_FLAG_STRING
))
196 int ENGINE_ctrl_cmd(ENGINE
*e
, const char *cmd_name
,
197 long i
, void *p
, void (*f
) (void), int cmd_optional
)
201 if (e
== NULL
|| cmd_name
== NULL
) {
202 ERR_raise(ERR_LIB_ENGINE
, ERR_R_PASSED_NULL_PARAMETER
);
206 || (num
= ENGINE_ctrl(e
, ENGINE_CTRL_GET_CMD_FROM_NAME
,
207 0, (void *)cmd_name
, NULL
)) <= 0) {
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
220 ERR_raise(ERR_LIB_ENGINE
, ENGINE_R_INVALID_CMD_NAME
);
224 * Force the result of the control command to 0 or 1, for the reasons
227 if (ENGINE_ctrl(e
, num
, i
, p
, f
) > 0)
232 int ENGINE_ctrl_cmd_string(ENGINE
*e
, const char *cmd_name
, const char *arg
,
239 if (e
== NULL
|| cmd_name
== NULL
) {
240 ERR_raise(ERR_LIB_ENGINE
, ERR_R_PASSED_NULL_PARAMETER
);
244 || (num
= ENGINE_ctrl(e
, ENGINE_CTRL_GET_CMD_FROM_NAME
,
245 0, (void *)cmd_name
, NULL
)) <= 0) {
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
258 ERR_raise(ERR_LIB_ENGINE
, ENGINE_R_INVALID_CMD_NAME
);
261 if (!ENGINE_cmd_is_executable(e
, num
)) {
262 ERR_raise(ERR_LIB_ENGINE
, ENGINE_R_CMD_NOT_EXECUTABLE
);
266 flags
= ENGINE_ctrl(e
, ENGINE_CTRL_GET_CMD_FLAGS
, num
, NULL
, NULL
);
269 * Shouldn't happen, given that ENGINE_cmd_is_executable() returned
272 ERR_raise(ERR_LIB_ENGINE
, ENGINE_R_INTERNAL_LIST_ERROR
);
276 * If the command takes no input, there must be no input. And vice versa.
278 if (flags
& ENGINE_CMD_FLAG_NO_INPUT
) {
280 ERR_raise(ERR_LIB_ENGINE
, ENGINE_R_COMMAND_TAKES_NO_INPUT
);
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.
289 if (ENGINE_ctrl(e
, num
, 0, (void *)arg
, NULL
) > 0)
293 /* So, we require input */
295 ERR_raise(ERR_LIB_ENGINE
, ENGINE_R_COMMAND_TAKES_INPUT
);
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)
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
311 if (!(flags
& ENGINE_CMD_FLAG_NUMERIC
)) {
312 ERR_raise(ERR_LIB_ENGINE
, ENGINE_R_INTERNAL_LIST_ERROR
);
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
);
321 * Force the result of the control command to 0 or 1, for the reasons
324 if (ENGINE_ctrl(e
, num
, l
, NULL
, NULL
) > 0)