1/* 2 * Copyright 2001-2021 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 */ 19static 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 27static 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 34static 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 47static 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 64static 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 128int 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 181int 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 196int 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 232int 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} 328