eng_ctrl.c revision 109998
1181834Sroberto/* crypto/engine/eng_ctrl.c */ 2181834Sroberto/* ==================================================================== 3290000Sglebius * Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved. 4181834Sroberto * 5181834Sroberto * Redistribution and use in source and binary forms, with or without 6181834Sroberto * modification, are permitted provided that the following conditions 7290000Sglebius * are met: 8290000Sglebius * 9290000Sglebius * 1. Redistributions of source code must retain the above copyright 10181834Sroberto * notice, this list of conditions and the following disclaimer. 11181834Sroberto * 12290000Sglebius * 2. Redistributions in binary form must reproduce the above copyright 13290000Sglebius * notice, this list of conditions and the following disclaimer in 14290000Sglebius * the documentation and/or other materials provided with the 15181834Sroberto * distribution. 16290000Sglebius * 17290000Sglebius * 3. All advertising materials mentioning features or use of this 18290000Sglebius * software must display the following acknowledgment: 19181834Sroberto * "This product includes software developed by the OpenSSL Project 20290000Sglebius * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 21290000Sglebius * 22181834Sroberto * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 23290000Sglebius * endorse or promote products derived from this software without 24290000Sglebius * prior written permission. For written permission, please contact 25181834Sroberto * licensing@OpenSSL.org. 26290000Sglebius * 27181834Sroberto * 5. Products derived from this software may not be called "OpenSSL" 28290000Sglebius * nor may "OpenSSL" appear in their names without prior written 29290000Sglebius * permission of the OpenSSL Project. 30290000Sglebius * 31181834Sroberto * 6. Redistributions of any form whatsoever must retain the following 32181834Sroberto * acknowledgment: 33181834Sroberto * "This product includes software developed by the OpenSSL Project 34181834Sroberto * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 35290000Sglebius * 36181834Sroberto * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 37181834Sroberto * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38181834Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39181834Sroberto * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 40181834Sroberto * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 41181834Sroberto * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 42181834Sroberto * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 43181834Sroberto * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44181834Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 45181834Sroberto * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46181834Sroberto * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 47181834Sroberto * OF THE POSSIBILITY OF SUCH DAMAGE. 48181834Sroberto * ==================================================================== 49181834Sroberto * 50181834Sroberto * This product includes cryptographic software written by Eric Young 51181834Sroberto * (eay@cryptsoft.com). This product includes software written by Tim 52181834Sroberto * Hudson (tjh@cryptsoft.com). 53181834Sroberto * 54181834Sroberto */ 55181834Sroberto 56290000Sglebius#include <openssl/crypto.h> 57290000Sglebius#include "cryptlib.h" 58290000Sglebius#include "eng_int.h" 59290000Sglebius#include <openssl/engine.h> 60290000Sglebius 61290000Sglebius/* When querying a ENGINE-specific control command's 'description', this string 62290000Sglebius * is used if the ENGINE_CMD_DEFN has cmd_desc set to NULL. */ 63290000Sglebiusstatic const char *int_no_description = ""; 64290000Sglebius 65290000Sglebius/* These internal functions handle 'CMD'-related control commands when the 66290000Sglebius * ENGINE in question has asked us to take care of it (ie. the ENGINE did not 67181834Sroberto * set the ENGINE_FLAGS_MANUAL_CMD_CTRL flag. */ 68181834Sroberto 69181834Srobertostatic int int_ctrl_cmd_is_null(const ENGINE_CMD_DEFN *defn) 70181834Sroberto { 71181834Sroberto if((defn->cmd_num == 0) || (defn->cmd_name == NULL)) 72181834Sroberto return 1; 73290000Sglebius return 0; 74290000Sglebius } 75290000Sglebius 76290000Sglebiusstatic int int_ctrl_cmd_by_name(const ENGINE_CMD_DEFN *defn, const char *s) 77290000Sglebius { 78290000Sglebius int idx = 0; 79290000Sglebius while(!int_ctrl_cmd_is_null(defn) && (strcmp(defn->cmd_name, s) != 0)) 80290000Sglebius { 81290000Sglebius idx++; 82290000Sglebius defn++; 83290000Sglebius } 84290000Sglebius if(int_ctrl_cmd_is_null(defn)) 85181834Sroberto /* The given name wasn't found */ 86290000Sglebius return -1; 87290000Sglebius return idx; 88290000Sglebius } 89181834Sroberto 90181834Srobertostatic int int_ctrl_cmd_by_num(const ENGINE_CMD_DEFN *defn, unsigned int num) 91181834Sroberto { 92290000Sglebius int idx = 0; 93290000Sglebius /* NB: It is stipulated that 'cmd_defn' lists are ordered by cmd_num. So 94290000Sglebius * our searches don't need to take any longer than necessary. */ 95181834Sroberto while(!int_ctrl_cmd_is_null(defn) && (defn->cmd_num < num)) 96181834Sroberto { 97290000Sglebius idx++; 98290000Sglebius defn++; 99290000Sglebius } 100290000Sglebius if(defn->cmd_num == num) 101290000Sglebius return idx; 102181834Sroberto /* The given cmd_num wasn't found */ 103181834Sroberto return -1; 104290000Sglebius } 105290000Sglebius 106290000Sglebiusstatic int int_ctrl_helper(ENGINE *e, int cmd, long i, void *p, void (*f)()) 107290000Sglebius { 108290000Sglebius int idx; 109290000Sglebius char *s = (char *)p; 110290000Sglebius /* Take care of the easy one first (eg. it requires no searches) */ 111290000Sglebius if(cmd == ENGINE_CTRL_GET_FIRST_CMD_TYPE) 112290000Sglebius { 113290000Sglebius if((e->cmd_defns == NULL) || int_ctrl_cmd_is_null(e->cmd_defns)) 114290000Sglebius return 0; 115290000Sglebius return e->cmd_defns->cmd_num; 116290000Sglebius } 117290000Sglebius /* One or two commands require that "p" be a valid string buffer */ 118290000Sglebius if((cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) || 119290000Sglebius (cmd == ENGINE_CTRL_GET_NAME_FROM_CMD) || 120290000Sglebius (cmd == ENGINE_CTRL_GET_DESC_FROM_CMD)) 121290000Sglebius { 122181834Sroberto if(s == NULL) 123181834Sroberto { 124181834Sroberto ENGINEerr(ENGINE_F_INT_CTRL_HELPER, 125181834Sroberto ERR_R_PASSED_NULL_PARAMETER); 126181834Sroberto return -1; 127181834Sroberto } 128181834Sroberto } 129181834Sroberto /* Now handle cmd_name -> cmd_num conversion */ 130290000Sglebius if(cmd == ENGINE_CTRL_GET_CMD_FROM_NAME) 131181834Sroberto { 132181834Sroberto if((e->cmd_defns == NULL) || ((idx = int_ctrl_cmd_by_name( 133290000Sglebius e->cmd_defns, s)) < 0)) 134290000Sglebius { 135290000Sglebius ENGINEerr(ENGINE_F_INT_CTRL_HELPER, 136290000Sglebius ENGINE_R_INVALID_CMD_NAME); 137181834Sroberto return -1; 138290000Sglebius } 139290000Sglebius return e->cmd_defns[idx].cmd_num; 140290000Sglebius } 141290000Sglebius /* For the rest of the commands, the 'long' argument must specify a 142181834Sroberto * valie command number - so we need to conduct a search. */ 143290000Sglebius if((e->cmd_defns == NULL) || ((idx = int_ctrl_cmd_by_num(e->cmd_defns, 144290000Sglebius (unsigned int)i)) < 0)) 145290000Sglebius { 146181834Sroberto ENGINEerr(ENGINE_F_INT_CTRL_HELPER, 147181834Sroberto ENGINE_R_INVALID_CMD_NUMBER); 148181834Sroberto return -1; 149181834Sroberto } 150290000Sglebius /* Now the logic splits depending on command type */ 151181834Sroberto switch(cmd) 152290000Sglebius { 153181834Sroberto case ENGINE_CTRL_GET_NEXT_CMD_TYPE: 154290000Sglebius idx++; 155181834Sroberto if(int_ctrl_cmd_is_null(e->cmd_defns + idx)) 156181834Sroberto /* end-of-list */ 157290000Sglebius return 0; 158290000Sglebius else 159290000Sglebius return e->cmd_defns[idx].cmd_num; 160290000Sglebius case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD: 161290000Sglebius return strlen(e->cmd_defns[idx].cmd_name); 162290000Sglebius case ENGINE_CTRL_GET_NAME_FROM_CMD: 163290000Sglebius return sprintf(s, "%s", e->cmd_defns[idx].cmd_name); 164290000Sglebius case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD: 165290000Sglebius if(e->cmd_defns[idx].cmd_desc) 166181834Sroberto return strlen(e->cmd_defns[idx].cmd_desc); 167290000Sglebius return strlen(int_no_description); 168290000Sglebius case ENGINE_CTRL_GET_DESC_FROM_CMD: 169290000Sglebius if(e->cmd_defns[idx].cmd_desc) 170290000Sglebius return sprintf(s, "%s", e->cmd_defns[idx].cmd_desc); 171290000Sglebius return sprintf(s, "%s", int_no_description); 172181834Sroberto case ENGINE_CTRL_GET_CMD_FLAGS: 173290000Sglebius return e->cmd_defns[idx].cmd_flags; 174290000Sglebius } 175290000Sglebius /* Shouldn't really be here ... */ 176290000Sglebius ENGINEerr(ENGINE_F_INT_CTRL_HELPER,ENGINE_R_INTERNAL_LIST_ERROR); 177181834Sroberto return -1; 178181834Sroberto } 179181834Sroberto 180290000Sglebiusint ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()) 181181834Sroberto { 182290000Sglebius int ctrl_exists, ref_exists; 183181834Sroberto if(e == NULL) 184181834Sroberto { 185181834Sroberto ENGINEerr(ENGINE_F_ENGINE_CTRL,ERR_R_PASSED_NULL_PARAMETER); 186181834Sroberto return 0; 187181834Sroberto } 188181834Sroberto CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 189181834Sroberto ref_exists = ((e->struct_ref > 0) ? 1 : 0); 190181834Sroberto CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 191290000Sglebius ctrl_exists = ((e->ctrl == NULL) ? 0 : 1); 192290000Sglebius if(!ref_exists) 193290000Sglebius { 194290000Sglebius ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_REFERENCE); 195290000Sglebius return 0; 196181834Sroberto } 197290000Sglebius /* Intercept any "root-level" commands before trying to hand them on to 198290000Sglebius * ctrl() handlers. */ 199290000Sglebius switch(cmd) 200290000Sglebius { 201181834Sroberto case ENGINE_CTRL_HAS_CTRL_FUNCTION: 202181834Sroberto return ctrl_exists; 203181834Sroberto case ENGINE_CTRL_GET_FIRST_CMD_TYPE: 204181834Sroberto case ENGINE_CTRL_GET_NEXT_CMD_TYPE: 205181834Sroberto case ENGINE_CTRL_GET_CMD_FROM_NAME: 206181834Sroberto case ENGINE_CTRL_GET_NAME_LEN_FROM_CMD: 207181834Sroberto case ENGINE_CTRL_GET_NAME_FROM_CMD: 208181834Sroberto case ENGINE_CTRL_GET_DESC_LEN_FROM_CMD: 209181834Sroberto case ENGINE_CTRL_GET_DESC_FROM_CMD: 210181834Sroberto case ENGINE_CTRL_GET_CMD_FLAGS: 211181834Sroberto if(ctrl_exists && !(e->flags & ENGINE_FLAGS_MANUAL_CMD_CTRL)) 212181834Sroberto return int_ctrl_helper(e,cmd,i,p,f); 213181834Sroberto if(!ctrl_exists) 214181834Sroberto { 215181834Sroberto ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_CONTROL_FUNCTION); 216181834Sroberto /* For these cmd-related functions, failure is indicated 217181834Sroberto * by a -1 return value (because 0 is used as a valid 218290000Sglebius * return in some places). */ 219290000Sglebius return -1; 220290000Sglebius } 221290000Sglebius default: 222181834Sroberto break; 223181834Sroberto } 224181834Sroberto /* Anything else requires a ctrl() handler to exist. */ 225181834Sroberto if(!ctrl_exists) 226181834Sroberto { 227290000Sglebius ENGINEerr(ENGINE_F_ENGINE_CTRL,ENGINE_R_NO_CONTROL_FUNCTION); 228290000Sglebius return 0; 229290000Sglebius } 230181834Sroberto return e->ctrl(e, cmd, i, p, f); 231181834Sroberto } 232181834Sroberto 233181834Srobertoint ENGINE_cmd_is_executable(ENGINE *e, int cmd) 234181834Sroberto { 235181834Sroberto int flags; 236181834Sroberto if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, cmd, NULL, NULL)) < 0) 237290000Sglebius { 238290000Sglebius ENGINEerr(ENGINE_F_ENGINE_CMD_IS_EXECUTABLE, 239290000Sglebius ENGINE_R_INVALID_CMD_NUMBER); 240290000Sglebius return 0; 241181834Sroberto } 242290000Sglebius if(!(flags & ENGINE_CMD_FLAG_NO_INPUT) && 243290000Sglebius !(flags & ENGINE_CMD_FLAG_NUMERIC) && 244290000Sglebius !(flags & ENGINE_CMD_FLAG_STRING)) 245290000Sglebius return 0; 246290000Sglebius return 1; 247290000Sglebius } 248290000Sglebius 249290000Sglebiusint ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name, 250290000Sglebius long i, void *p, void (*f)(), int cmd_optional) 251290000Sglebius { 252290000Sglebius int num; 253290000Sglebius 254290000Sglebius if((e == NULL) || (cmd_name == NULL)) 255290000Sglebius { 256290000Sglebius ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 257181834Sroberto ERR_R_PASSED_NULL_PARAMETER); 258181834Sroberto return 0; 259290000Sglebius } 260290000Sglebius if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e, 261290000Sglebius ENGINE_CTRL_GET_CMD_FROM_NAME, 262290000Sglebius 0, (void *)cmd_name, NULL)) <= 0)) 263181834Sroberto { 264181834Sroberto /* If the command didn't *have* to be supported, we fake 265290000Sglebius * success. This allows certain settings to be specified for 266181834Sroberto * multiple ENGINEs and only require a change of ENGINE id 267181834Sroberto * (without having to selectively apply settings). Eg. changing 268290000Sglebius * from a hardware device back to the regular software ENGINE 269181834Sroberto * without editing the config file, etc. */ 270290000Sglebius if(cmd_optional) 271181834Sroberto { 272181834Sroberto ERR_clear_error(); 273290000Sglebius return 1; 274181834Sroberto } 275290000Sglebius ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD, 276181834Sroberto ENGINE_R_INVALID_CMD_NAME); 277181834Sroberto return 0; 278181834Sroberto } 279181834Sroberto /* Force the result of the control command to 0 or 1, for the reasons 280181834Sroberto * mentioned before. */ 281181834Sroberto if (ENGINE_ctrl(e, num, i, p, f)) 282181834Sroberto return 1; 283181834Sroberto return 0; 284181834Sroberto } 285181834Sroberto 286181834Srobertoint ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg, 287181834Sroberto int cmd_optional) 288181834Sroberto { 289181834Sroberto int num, flags; 290181834Sroberto long l; 291181834Sroberto char *ptr; 292181834Sroberto if((e == NULL) || (cmd_name == NULL)) 293181834Sroberto { 294181834Sroberto ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 295181834Sroberto ERR_R_PASSED_NULL_PARAMETER); 296181834Sroberto return 0; 297181834Sroberto } 298181834Sroberto if((e->ctrl == NULL) || ((num = ENGINE_ctrl(e, 299181834Sroberto ENGINE_CTRL_GET_CMD_FROM_NAME, 300181834Sroberto 0, (void *)cmd_name, NULL)) <= 0)) 301181834Sroberto { 302181834Sroberto /* If the command didn't *have* to be supported, we fake 303181834Sroberto * success. This allows certain settings to be specified for 304181834Sroberto * multiple ENGINEs and only require a change of ENGINE id 305290000Sglebius * (without having to selectively apply settings). Eg. changing 306290000Sglebius * from a hardware device back to the regular software ENGINE 307181834Sroberto * without editing the config file, etc. */ 308181834Sroberto if(cmd_optional) 309181834Sroberto { 310181834Sroberto ERR_clear_error(); 311181834Sroberto return 1; 312181834Sroberto } 313181834Sroberto ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 314181834Sroberto ENGINE_R_INVALID_CMD_NAME); 315181834Sroberto return 0; 316181834Sroberto } 317181834Sroberto if(!ENGINE_cmd_is_executable(e, num)) 318181834Sroberto { 319181834Sroberto ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 320181834Sroberto ENGINE_R_CMD_NOT_EXECUTABLE); 321181834Sroberto return 0; 322181834Sroberto } 323181834Sroberto if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, NULL, NULL)) < 0) 324181834Sroberto { 325181834Sroberto /* Shouldn't happen, given that ENGINE_cmd_is_executable() 326181834Sroberto * returned success. */ 327290000Sglebius ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 328290000Sglebius ENGINE_R_INTERNAL_LIST_ERROR); 329181834Sroberto return 0; 330181834Sroberto } 331181834Sroberto /* If the command takes no input, there must be no input. And vice 332181834Sroberto * versa. */ 333181834Sroberto if(flags & ENGINE_CMD_FLAG_NO_INPUT) 334181834Sroberto { 335181834Sroberto if(arg != NULL) 336181834Sroberto { 337181834Sroberto ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 338181834Sroberto ENGINE_R_COMMAND_TAKES_NO_INPUT); 339181834Sroberto return 0; 340181834Sroberto } 341181834Sroberto /* We deliberately force the result of ENGINE_ctrl() to 0 or 1 342181834Sroberto * rather than returning it as "return data". This is to ensure 343181834Sroberto * usage of these commands is consistent across applications and 344181834Sroberto * that certain applications don't understand it one way, and 345181834Sroberto * others another. */ 346181834Sroberto if(ENGINE_ctrl(e, num, 0, (void *)arg, NULL)) 347181834Sroberto return 1; 348181834Sroberto return 0; 349181834Sroberto } 350181834Sroberto /* So, we require input */ 351181834Sroberto if(arg == NULL) 352181834Sroberto { 353181834Sroberto ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 354181834Sroberto ENGINE_R_COMMAND_TAKES_INPUT); 355181834Sroberto return 0; 356181834Sroberto } 357181834Sroberto /* If it takes string input, that's easy */ 358181834Sroberto if(flags & ENGINE_CMD_FLAG_STRING) 359181834Sroberto { 360181834Sroberto /* Same explanation as above */ 361181834Sroberto if(ENGINE_ctrl(e, num, 0, (void *)arg, NULL)) 362181834Sroberto return 1; 363181834Sroberto return 0; 364181834Sroberto } 365181834Sroberto /* If it doesn't take numeric either, then it is unsupported for use in 366181834Sroberto * a config-setting situation, which is what this function is for. This 367181834Sroberto * should never happen though, because ENGINE_cmd_is_executable() was 368181834Sroberto * used. */ 369181834Sroberto if(!(flags & ENGINE_CMD_FLAG_NUMERIC)) 370181834Sroberto { 371181834Sroberto ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 372290000Sglebius ENGINE_R_INTERNAL_LIST_ERROR); 373181834Sroberto return 0; 374181834Sroberto } 375181834Sroberto l = strtol(arg, &ptr, 10); 376181834Sroberto if((arg == ptr) || (*ptr != '\0')) 377181834Sroberto { 378181834Sroberto ENGINEerr(ENGINE_F_ENGINE_CTRL_CMD_STRING, 379181834Sroberto ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER); 380181834Sroberto return 0; 381181834Sroberto } 382290000Sglebius /* Force the result of the control command to 0 or 1, for the reasons 383290000Sglebius * mentioned before. */ 384181834Sroberto if(ENGINE_ctrl(e, num, l, NULL, NULL)) 385181834Sroberto return 1; 386290000Sglebius return 0; 387290000Sglebius } 388290000Sglebius