1 /* 2 * Copyright 2001-2022 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_local.h" 11 #include "internal/dso.h" 12 #include <openssl/crypto.h> 13 14 /* 15 * Shared libraries implementing ENGINEs for use by the "dynamic" ENGINE 16 * loader should implement the hook-up functions with the following 17 * prototypes. 18 */ 19 20 /* Our ENGINE handlers */ 21 static int dynamic_init(ENGINE *e); 22 static int dynamic_finish(ENGINE *e); 23 static int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p, 24 void (*f) (void)); 25 /* Predeclare our context type */ 26 typedef struct st_dynamic_data_ctx dynamic_data_ctx; 27 /* The implementation for the important control command */ 28 static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx); 29 30 #define DYNAMIC_CMD_SO_PATH ENGINE_CMD_BASE 31 #define DYNAMIC_CMD_NO_VCHECK (ENGINE_CMD_BASE + 1) 32 #define DYNAMIC_CMD_ID (ENGINE_CMD_BASE + 2) 33 #define DYNAMIC_CMD_LIST_ADD (ENGINE_CMD_BASE + 3) 34 #define DYNAMIC_CMD_DIR_LOAD (ENGINE_CMD_BASE + 4) 35 #define DYNAMIC_CMD_DIR_ADD (ENGINE_CMD_BASE + 5) 36 #define DYNAMIC_CMD_LOAD (ENGINE_CMD_BASE + 6) 37 38 /* The constants used when creating the ENGINE */ 39 static const char *engine_dynamic_id = "dynamic"; 40 static const char *engine_dynamic_name = "Dynamic engine loading support"; 41 static const ENGINE_CMD_DEFN dynamic_cmd_defns[] = { 42 {DYNAMIC_CMD_SO_PATH, 43 "SO_PATH", 44 "Specifies the path to the new ENGINE shared library", 45 ENGINE_CMD_FLAG_STRING}, 46 {DYNAMIC_CMD_NO_VCHECK, 47 "NO_VCHECK", 48 "Specifies to continue even if version checking fails (boolean)", 49 ENGINE_CMD_FLAG_NUMERIC}, 50 {DYNAMIC_CMD_ID, 51 "ID", 52 "Specifies an ENGINE id name for loading", 53 ENGINE_CMD_FLAG_STRING}, 54 {DYNAMIC_CMD_LIST_ADD, 55 "LIST_ADD", 56 "Whether to add a loaded ENGINE to the internal list (0=no,1=yes,2=mandatory)", 57 ENGINE_CMD_FLAG_NUMERIC}, 58 {DYNAMIC_CMD_DIR_LOAD, 59 "DIR_LOAD", 60 "Specifies whether to load from 'DIR_ADD' directories (0=no,1=yes,2=mandatory)", 61 ENGINE_CMD_FLAG_NUMERIC}, 62 {DYNAMIC_CMD_DIR_ADD, 63 "DIR_ADD", 64 "Adds a directory from which ENGINEs can be loaded", 65 ENGINE_CMD_FLAG_STRING}, 66 {DYNAMIC_CMD_LOAD, 67 "LOAD", 68 "Load up the ENGINE specified by other settings", 69 ENGINE_CMD_FLAG_NO_INPUT}, 70 {0, NULL, NULL, 0} 71 }; 72 73 /* 74 * Loading code stores state inside the ENGINE structure via the "ex_data" 75 * element. We load all our state into a single structure and use that as a 76 * single context in the "ex_data" stack. 77 */ 78 struct st_dynamic_data_ctx { 79 /* The DSO object we load that supplies the ENGINE code */ 80 DSO *dynamic_dso; 81 /* 82 * The function pointer to the version checking shared library function 83 */ 84 dynamic_v_check_fn v_check; 85 /* 86 * The function pointer to the engine-binding shared library function 87 */ 88 dynamic_bind_engine bind_engine; 89 /* The default name/path for loading the shared library */ 90 char *DYNAMIC_LIBNAME; 91 /* Whether to continue loading on a version check failure */ 92 int no_vcheck; 93 /* If non-NULL, stipulates the 'id' of the ENGINE to be loaded */ 94 char *engine_id; 95 /* 96 * If non-zero, a successfully loaded ENGINE should be added to the 97 * internal ENGINE list. If 2, the add must succeed or the entire load 98 * should fail. 99 */ 100 int list_add_value; 101 /* The symbol name for the version checking function */ 102 const char *DYNAMIC_F1; 103 /* The symbol name for the "initialise ENGINE structure" function */ 104 const char *DYNAMIC_F2; 105 /* 106 * Whether to never use 'dirs', use 'dirs' as a fallback, or only use 107 * 'dirs' for loading. Default is to use 'dirs' as a fallback. 108 */ 109 int dir_load; 110 /* A stack of directories from which ENGINEs could be loaded */ 111 STACK_OF(OPENSSL_STRING) *dirs; 112 }; 113 114 /* 115 * This is the "ex_data" index we obtain and reserve for use with our context 116 * structure. 117 */ 118 static int dynamic_ex_data_idx = -1; 119 120 static void int_free_str(char *s) 121 { 122 OPENSSL_free(s); 123 } 124 125 /* 126 * Because our ex_data element may or may not get allocated depending on 127 * whether a "first-use" occurs before the ENGINE is freed, we have a memory 128 * leak problem to solve. We can't declare a "new" handler for the ex_data as 129 * we don't want a dynamic_data_ctx in *all* ENGINE structures of all types 130 * (this is a bug in the design of CRYPTO_EX_DATA). As such, we just declare 131 * a "free" handler and that will get called if an ENGINE is being destroyed 132 * and there was an ex_data element corresponding to our context type. 133 */ 134 static void dynamic_data_ctx_free_func(void *parent, void *ptr, 135 CRYPTO_EX_DATA *ad, int idx, long argl, 136 void *argp) 137 { 138 if (ptr) { 139 dynamic_data_ctx *ctx = (dynamic_data_ctx *)ptr; 140 DSO_free(ctx->dynamic_dso); 141 OPENSSL_free(ctx->DYNAMIC_LIBNAME); 142 OPENSSL_free(ctx->engine_id); 143 sk_OPENSSL_STRING_pop_free(ctx->dirs, int_free_str); 144 OPENSSL_free(ctx); 145 } 146 } 147 148 /* 149 * Construct the per-ENGINE context. We create it blindly and then use a lock 150 * to check for a race - if so, all but one of the threads "racing" will have 151 * wasted their time. The alternative involves creating everything inside the 152 * lock which is far worse. 153 */ 154 static int dynamic_set_data_ctx(ENGINE *e, dynamic_data_ctx **ctx) 155 { 156 dynamic_data_ctx *c = OPENSSL_zalloc(sizeof(*c)); 157 int ret = 1; 158 159 if (c == NULL) { 160 ENGINEerr(ENGINE_F_DYNAMIC_SET_DATA_CTX, ERR_R_MALLOC_FAILURE); 161 return 0; 162 } 163 c->dirs = sk_OPENSSL_STRING_new_null(); 164 if (c->dirs == NULL) { 165 ENGINEerr(ENGINE_F_DYNAMIC_SET_DATA_CTX, ERR_R_MALLOC_FAILURE); 166 OPENSSL_free(c); 167 return 0; 168 } 169 c->DYNAMIC_F1 = "v_check"; 170 c->DYNAMIC_F2 = "bind_engine"; 171 c->dir_load = 1; 172 CRYPTO_THREAD_write_lock(global_engine_lock); 173 if ((*ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e, 174 dynamic_ex_data_idx)) 175 == NULL) { 176 /* Good, we're the first */ 177 ret = ENGINE_set_ex_data(e, dynamic_ex_data_idx, c); 178 if (ret) { 179 *ctx = c; 180 c = NULL; 181 } 182 } 183 CRYPTO_THREAD_unlock(global_engine_lock); 184 /* 185 * If we lost the race to set the context, c is non-NULL and *ctx is the 186 * context of the thread that won. 187 */ 188 if (c) 189 sk_OPENSSL_STRING_free(c->dirs); 190 OPENSSL_free(c); 191 return ret; 192 } 193 194 /* 195 * This function retrieves the context structure from an ENGINE's "ex_data", 196 * or if it doesn't exist yet, sets it up. 197 */ 198 static dynamic_data_ctx *dynamic_get_data_ctx(ENGINE *e) 199 { 200 dynamic_data_ctx *ctx; 201 if (dynamic_ex_data_idx < 0) { 202 /* 203 * Create and register the ENGINE ex_data, and associate our "free" 204 * function with it to ensure any allocated contexts get freed when 205 * an ENGINE goes underground. 206 */ 207 int new_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, 208 dynamic_data_ctx_free_func); 209 if (new_idx == -1) { 210 ENGINEerr(ENGINE_F_DYNAMIC_GET_DATA_CTX, ENGINE_R_NO_INDEX); 211 return NULL; 212 } 213 CRYPTO_THREAD_write_lock(global_engine_lock); 214 /* Avoid a race by checking again inside this lock */ 215 if (dynamic_ex_data_idx < 0) { 216 /* Good, someone didn't beat us to it */ 217 dynamic_ex_data_idx = new_idx; 218 new_idx = -1; 219 } 220 CRYPTO_THREAD_unlock(global_engine_lock); 221 /* 222 * In theory we could "give back" the index here if (new_idx>-1), but 223 * it's not possible and wouldn't gain us much if it were. 224 */ 225 } 226 ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e, dynamic_ex_data_idx); 227 /* Check if the context needs to be created */ 228 if ((ctx == NULL) && !dynamic_set_data_ctx(e, &ctx)) 229 /* "set_data" will set errors if necessary */ 230 return NULL; 231 return ctx; 232 } 233 234 static ENGINE *engine_dynamic(void) 235 { 236 ENGINE *ret = ENGINE_new(); 237 if (ret == NULL) 238 return NULL; 239 if (!ENGINE_set_id(ret, engine_dynamic_id) || 240 !ENGINE_set_name(ret, engine_dynamic_name) || 241 !ENGINE_set_init_function(ret, dynamic_init) || 242 !ENGINE_set_finish_function(ret, dynamic_finish) || 243 !ENGINE_set_ctrl_function(ret, dynamic_ctrl) || 244 !ENGINE_set_flags(ret, ENGINE_FLAGS_BY_ID_COPY) || 245 !ENGINE_set_cmd_defns(ret, dynamic_cmd_defns)) { 246 ENGINE_free(ret); 247 return NULL; 248 } 249 return ret; 250 } 251 252 void engine_load_dynamic_int(void) 253 { 254 ENGINE *toadd = engine_dynamic(); 255 if (!toadd) 256 return; 257 ENGINE_add(toadd); 258 /* 259 * If the "add" worked, it gets a structural reference. So either way, we 260 * release our just-created reference. 261 */ 262 ENGINE_free(toadd); 263 /* 264 * If the "add" didn't work, it was probably a conflict because it was 265 * already added (eg. someone calling ENGINE_load_blah then calling 266 * ENGINE_load_builtin_engines() perhaps). 267 */ 268 ERR_clear_error(); 269 } 270 271 static int dynamic_init(ENGINE *e) 272 { 273 /* 274 * We always return failure - the "dynamic" engine itself can't be used 275 * for anything. 276 */ 277 return 0; 278 } 279 280 static int dynamic_finish(ENGINE *e) 281 { 282 /* 283 * This should never be called on account of "dynamic_init" always 284 * failing. 285 */ 286 return 0; 287 } 288 289 static int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) 290 { 291 dynamic_data_ctx *ctx = dynamic_get_data_ctx(e); 292 int initialised; 293 294 if (!ctx) { 295 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_NOT_LOADED); 296 return 0; 297 } 298 initialised = ((ctx->dynamic_dso == NULL) ? 0 : 1); 299 /* All our control commands require the ENGINE to be uninitialised */ 300 if (initialised) { 301 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_ALREADY_LOADED); 302 return 0; 303 } 304 switch (cmd) { 305 case DYNAMIC_CMD_SO_PATH: 306 /* a NULL 'p' or a string of zero-length is the same thing */ 307 if (p && (strlen((const char *)p) < 1)) 308 p = NULL; 309 OPENSSL_free(ctx->DYNAMIC_LIBNAME); 310 if (p) 311 ctx->DYNAMIC_LIBNAME = OPENSSL_strdup(p); 312 else 313 ctx->DYNAMIC_LIBNAME = NULL; 314 return (ctx->DYNAMIC_LIBNAME ? 1 : 0); 315 case DYNAMIC_CMD_NO_VCHECK: 316 ctx->no_vcheck = ((i == 0) ? 0 : 1); 317 return 1; 318 case DYNAMIC_CMD_ID: 319 /* a NULL 'p' or a string of zero-length is the same thing */ 320 if (p && (strlen((const char *)p) < 1)) 321 p = NULL; 322 OPENSSL_free(ctx->engine_id); 323 if (p) 324 ctx->engine_id = OPENSSL_strdup(p); 325 else 326 ctx->engine_id = NULL; 327 return (ctx->engine_id ? 1 : 0); 328 case DYNAMIC_CMD_LIST_ADD: 329 if ((i < 0) || (i > 2)) { 330 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_INVALID_ARGUMENT); 331 return 0; 332 } 333 ctx->list_add_value = (int)i; 334 return 1; 335 case DYNAMIC_CMD_LOAD: 336 return dynamic_load(e, ctx); 337 case DYNAMIC_CMD_DIR_LOAD: 338 if ((i < 0) || (i > 2)) { 339 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_INVALID_ARGUMENT); 340 return 0; 341 } 342 ctx->dir_load = (int)i; 343 return 1; 344 case DYNAMIC_CMD_DIR_ADD: 345 /* a NULL 'p' or a string of zero-length is the same thing */ 346 if (!p || (strlen((const char *)p) < 1)) { 347 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_INVALID_ARGUMENT); 348 return 0; 349 } 350 { 351 char *tmp_str = OPENSSL_strdup(p); 352 if (tmp_str == NULL) { 353 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ERR_R_MALLOC_FAILURE); 354 return 0; 355 } 356 if (!sk_OPENSSL_STRING_push(ctx->dirs, tmp_str)) { 357 OPENSSL_free(tmp_str); 358 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ERR_R_MALLOC_FAILURE); 359 return 0; 360 } 361 } 362 return 1; 363 default: 364 break; 365 } 366 ENGINEerr(ENGINE_F_DYNAMIC_CTRL, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED); 367 return 0; 368 } 369 370 static int int_load(dynamic_data_ctx *ctx) 371 { 372 int num, loop; 373 /* Unless told not to, try a direct load */ 374 if ((ctx->dir_load != 2) && (DSO_load(ctx->dynamic_dso, 375 ctx->DYNAMIC_LIBNAME, NULL, 376 0)) != NULL) 377 return 1; 378 /* If we're not allowed to use 'dirs' or we have none, fail */ 379 if (!ctx->dir_load || (num = sk_OPENSSL_STRING_num(ctx->dirs)) < 1) 380 return 0; 381 for (loop = 0; loop < num; loop++) { 382 const char *s = sk_OPENSSL_STRING_value(ctx->dirs, loop); 383 char *merge = DSO_merge(ctx->dynamic_dso, ctx->DYNAMIC_LIBNAME, s); 384 if (!merge) 385 return 0; 386 if (DSO_load(ctx->dynamic_dso, merge, NULL, 0)) { 387 /* Found what we're looking for */ 388 OPENSSL_free(merge); 389 return 1; 390 } 391 OPENSSL_free(merge); 392 } 393 return 0; 394 } 395 396 /* 397 * Unfortunately the version checker does not distinguish between 398 * engines built for openssl 1.1.x and openssl 3.x, but loading 399 * an engine that is built for openssl 3.x will cause a fatal 400 * error. Detect such engines, since EVP_PKEY_get_base_id is exported 401 * as a function in openssl 3.x, while it is named EVP_PKEY_base_id 402 * in openssl 1.1.x. Therefore we take the presence of that symbol 403 * as an indication that the engine will be incompatible. 404 */ 405 static int using_libcrypto_3(dynamic_data_ctx *ctx) 406 { 407 int ret; 408 409 ERR_set_mark(); 410 ret = DSO_bind_func(ctx->dynamic_dso, "EVP_PKEY_get_base_id") != NULL; 411 ERR_pop_to_mark(); 412 413 return ret; 414 } 415 416 static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx) 417 { 418 ENGINE cpy; 419 dynamic_fns fns; 420 421 if (ctx->dynamic_dso == NULL) 422 ctx->dynamic_dso = DSO_new(); 423 if (ctx->dynamic_dso == NULL) 424 return 0; 425 if (!ctx->DYNAMIC_LIBNAME) { 426 if (!ctx->engine_id) 427 return 0; 428 DSO_ctrl(ctx->dynamic_dso, DSO_CTRL_SET_FLAGS, 429 DSO_FLAG_NAME_TRANSLATION_EXT_ONLY, NULL); 430 ctx->DYNAMIC_LIBNAME = 431 DSO_convert_filename(ctx->dynamic_dso, ctx->engine_id); 432 } 433 if (!int_load(ctx)) { 434 ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_DSO_NOT_FOUND); 435 DSO_free(ctx->dynamic_dso); 436 ctx->dynamic_dso = NULL; 437 return 0; 438 } 439 /* We have to find a bind function otherwise it'll always end badly */ 440 if (! 441 (ctx->bind_engine = 442 (dynamic_bind_engine) DSO_bind_func(ctx->dynamic_dso, 443 ctx->DYNAMIC_F2))) { 444 ctx->bind_engine = NULL; 445 DSO_free(ctx->dynamic_dso); 446 ctx->dynamic_dso = NULL; 447 ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_DSO_FAILURE); 448 return 0; 449 } 450 /* Do we perform version checking? */ 451 if (!ctx->no_vcheck) { 452 unsigned long vcheck_res = 0; 453 /* 454 * Now we try to find a version checking function and decide how to 455 * cope with failure if/when it fails. 456 */ 457 ctx->v_check = 458 (dynamic_v_check_fn) DSO_bind_func(ctx->dynamic_dso, 459 ctx->DYNAMIC_F1); 460 if (ctx->v_check) 461 vcheck_res = ctx->v_check(OSSL_DYNAMIC_VERSION); 462 /* 463 * We fail if the version checker veto'd the load *or* if it is 464 * deferring to us (by returning its version) and we think it is too 465 * old. Also fail if this is engine for openssl 3.x. 466 */ 467 if (vcheck_res < OSSL_DYNAMIC_OLDEST || using_libcrypto_3(ctx)) { 468 /* Fail */ 469 ctx->bind_engine = NULL; 470 ctx->v_check = NULL; 471 DSO_free(ctx->dynamic_dso); 472 ctx->dynamic_dso = NULL; 473 ENGINEerr(ENGINE_F_DYNAMIC_LOAD, 474 ENGINE_R_VERSION_INCOMPATIBILITY); 475 return 0; 476 } 477 } 478 /* 479 * First binary copy the ENGINE structure so that we can roll back if the 480 * hand-over fails 481 */ 482 memcpy(&cpy, e, sizeof(ENGINE)); 483 /* 484 * Provide the ERR, "ex_data", memory, and locking callbacks so the 485 * loaded library uses our state rather than its own. FIXME: As noted in 486 * engine.h, much of this would be simplified if each area of code 487 * provided its own "summary" structure of all related callbacks. It 488 * would also increase opaqueness. 489 */ 490 fns.static_state = ENGINE_get_static_state(); 491 CRYPTO_get_mem_functions(&fns.mem_fns.malloc_fn, &fns.mem_fns.realloc_fn, 492 &fns.mem_fns.free_fn); 493 /* 494 * Now that we've loaded the dynamic engine, make sure no "dynamic" 495 * ENGINE elements will show through. 496 */ 497 engine_set_all_null(e); 498 499 /* Try to bind the ENGINE onto our own ENGINE structure */ 500 if (!engine_add_dynamic_id(e, (ENGINE_DYNAMIC_ID)ctx->bind_engine, 1) 501 || !ctx->bind_engine(e, ctx->engine_id, &fns)) { 502 engine_remove_dynamic_id(e, 1); 503 ctx->bind_engine = NULL; 504 ctx->v_check = NULL; 505 DSO_free(ctx->dynamic_dso); 506 ctx->dynamic_dso = NULL; 507 ENGINEerr(ENGINE_F_DYNAMIC_LOAD, ENGINE_R_INIT_FAILED); 508 /* Copy the original ENGINE structure back */ 509 memcpy(e, &cpy, sizeof(ENGINE)); 510 return 0; 511 } 512 /* Do we try to add this ENGINE to the internal list too? */ 513 if (ctx->list_add_value > 0) { 514 if (!ENGINE_add(e)) { 515 /* Do we tolerate this or fail? */ 516 if (ctx->list_add_value > 1) { 517 /* 518 * Fail - NB: By this time, it's too late to rollback, and 519 * trying to do so allows the bind_engine() code to have 520 * created leaks. We just have to fail where we are, after 521 * the ENGINE has changed. 522 */ 523 ENGINEerr(ENGINE_F_DYNAMIC_LOAD, 524 ENGINE_R_CONFLICTING_ENGINE_ID); 525 return 0; 526 } 527 /* Tolerate */ 528 ERR_clear_error(); 529 } 530 } 531 return 1; 532 } 533