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 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) || (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 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 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 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 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