1 /* 2 * Copyright 2001-2024 The OpenSSL Project Authors. All Rights Reserved. 3 * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved 4 * 5 * Licensed under the Apache License 2.0 (the "License"). You may not use 6 * this file except in compliance with the License. You can obtain a copy 7 * in the file LICENSE in the source distribution or at 8 * https://www.openssl.org/source/license.html 9 */ 10 11 /* We need to use some engine deprecated APIs */ 12 #define OPENSSL_SUPPRESS_DEPRECATED 13 14 #include "eng_local.h" 15 16 /* 17 * The linked-list of pointers to engine types. engine_list_head incorporates 18 * an implicit structural reference but engine_list_tail does not - the 19 * latter is a computational optimization and only points to something that 20 * is already pointed to by its predecessor in the list (or engine_list_head 21 * itself). In the same way, the use of the "prev" pointer in each ENGINE is 22 * to save excessive list iteration, it doesn't correspond to an extra 23 * structural reference. Hence, engine_list_head, and each non-null "next" 24 * pointer account for the list itself assuming exactly 1 structural 25 * reference on each list member. 26 */ 27 static ENGINE *engine_list_head = NULL; 28 static ENGINE *engine_list_tail = NULL; 29 30 /* 31 * The linked list of currently loaded dynamic engines. 32 */ 33 static ENGINE *engine_dyn_list_head = NULL; 34 static ENGINE *engine_dyn_list_tail = NULL; 35 36 /* 37 * This cleanup function is only needed internally. If it should be called, 38 * we register it with the "engine_cleanup_int()" stack to be called during 39 * cleanup. 40 */ 41 42 static void engine_list_cleanup(void) 43 { 44 ENGINE *iterator = engine_list_head; 45 46 while (iterator != NULL) { 47 ENGINE_remove(iterator); 48 iterator = engine_list_head; 49 } 50 return; 51 } 52 53 /* 54 * These static functions starting with a lower case "engine_" always take 55 * place when global_engine_lock has been locked up. 56 */ 57 static int engine_list_add(ENGINE *e) 58 { 59 int conflict = 0; 60 ENGINE *iterator = NULL; 61 int ref; 62 63 if (e == NULL) { 64 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER); 65 return 0; 66 } 67 iterator = engine_list_head; 68 while (iterator && !conflict) { 69 conflict = (strcmp(iterator->id, e->id) == 0); 70 iterator = iterator->next; 71 } 72 if (conflict) { 73 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_CONFLICTING_ENGINE_ID); 74 return 0; 75 } 76 77 /* 78 * Having the engine in the list assumes a structural reference. 79 */ 80 if (!CRYPTO_UP_REF(&e->struct_ref, &ref)) { 81 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR); 82 return 0; 83 } 84 ENGINE_REF_PRINT(e, 0, 1); 85 if (engine_list_head == NULL) { 86 /* We are adding to an empty list. */ 87 if (engine_list_tail != NULL) { 88 CRYPTO_DOWN_REF(&e->struct_ref, &ref); 89 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR); 90 return 0; 91 } 92 /* 93 * The first time the list allocates, we should register the cleanup. 94 */ 95 if (!engine_cleanup_add_last(engine_list_cleanup)) { 96 CRYPTO_DOWN_REF(&e->struct_ref, &ref); 97 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR); 98 return 0; 99 } 100 engine_list_head = e; 101 e->prev = NULL; 102 } else { 103 /* We are adding to the tail of an existing list. */ 104 if ((engine_list_tail == NULL) || (engine_list_tail->next != NULL)) { 105 CRYPTO_DOWN_REF(&e->struct_ref, &ref); 106 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR); 107 return 0; 108 } 109 engine_list_tail->next = e; 110 e->prev = engine_list_tail; 111 } 112 113 /* However it came to be, e is the last item in the list. */ 114 engine_list_tail = e; 115 e->next = NULL; 116 return 1; 117 } 118 119 static int engine_list_remove(ENGINE *e) 120 { 121 ENGINE *iterator; 122 123 if (e == NULL) { 124 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER); 125 return 0; 126 } 127 /* We need to check that e is in our linked list! */ 128 iterator = engine_list_head; 129 while (iterator && (iterator != e)) 130 iterator = iterator->next; 131 if (iterator == NULL) { 132 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ENGINE_IS_NOT_IN_LIST); 133 return 0; 134 } 135 /* un-link e from the chain. */ 136 if (e->next) 137 e->next->prev = e->prev; 138 if (e->prev) 139 e->prev->next = e->next; 140 /* Correct our head/tail if necessary. */ 141 if (engine_list_head == e) 142 engine_list_head = e->next; 143 if (engine_list_tail == e) 144 engine_list_tail = e->prev; 145 engine_free_util(e, 0); 146 return 1; 147 } 148 149 /* Add engine to dynamic engine list. */ 150 int engine_add_dynamic_id(ENGINE *e, ENGINE_DYNAMIC_ID dynamic_id, 151 int not_locked) 152 { 153 int result = 0; 154 ENGINE *iterator = NULL; 155 156 if (e == NULL) 157 return 0; 158 159 if (e->dynamic_id == NULL && dynamic_id == NULL) 160 return 0; 161 162 if (not_locked && !CRYPTO_THREAD_write_lock(global_engine_lock)) 163 return 0; 164 165 if (dynamic_id != NULL) { 166 iterator = engine_dyn_list_head; 167 while (iterator != NULL) { 168 if (iterator->dynamic_id == dynamic_id) 169 goto err; 170 iterator = iterator->next; 171 } 172 if (e->dynamic_id != NULL) 173 goto err; 174 e->dynamic_id = dynamic_id; 175 } 176 177 if (engine_dyn_list_head == NULL) { 178 /* We are adding to an empty list. */ 179 if (engine_dyn_list_tail != NULL) 180 goto err; 181 engine_dyn_list_head = e; 182 e->prev_dyn = NULL; 183 } else { 184 /* We are adding to the tail of an existing list. */ 185 if (engine_dyn_list_tail == NULL 186 || engine_dyn_list_tail->next_dyn != NULL) 187 goto err; 188 engine_dyn_list_tail->next_dyn = e; 189 e->prev_dyn = engine_dyn_list_tail; 190 } 191 192 engine_dyn_list_tail = e; 193 e->next_dyn = NULL; 194 result = 1; 195 196 err: 197 if (not_locked) 198 CRYPTO_THREAD_unlock(global_engine_lock); 199 return result; 200 } 201 202 /* Remove engine from dynamic engine list. */ 203 void engine_remove_dynamic_id(ENGINE *e, int not_locked) 204 { 205 if (e == NULL || e->dynamic_id == NULL) 206 return; 207 208 if (not_locked && !CRYPTO_THREAD_write_lock(global_engine_lock)) 209 return; 210 211 e->dynamic_id = NULL; 212 213 /* un-link e from the chain. */ 214 if (e->next_dyn != NULL) 215 e->next_dyn->prev_dyn = e->prev_dyn; 216 if (e->prev_dyn != NULL) 217 e->prev_dyn->next_dyn = e->next_dyn; 218 /* Correct our head/tail if necessary. */ 219 if (engine_dyn_list_head == e) 220 engine_dyn_list_head = e->next_dyn; 221 if (engine_dyn_list_tail == e) 222 engine_dyn_list_tail = e->prev_dyn; 223 224 if (not_locked) 225 CRYPTO_THREAD_unlock(global_engine_lock); 226 } 227 228 /* Get the first/last "ENGINE" type available. */ 229 ENGINE *ENGINE_get_first(void) 230 { 231 ENGINE *ret; 232 233 if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) { 234 /* Maybe this should be raised in do_engine_lock_init() */ 235 ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); 236 return NULL; 237 } 238 239 if (!CRYPTO_THREAD_write_lock(global_engine_lock)) 240 return NULL; 241 ret = engine_list_head; 242 if (ret) { 243 int ref; 244 245 if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) { 246 CRYPTO_THREAD_unlock(global_engine_lock); 247 ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); 248 return NULL; 249 } 250 ENGINE_REF_PRINT(ret, 0, 1); 251 } 252 CRYPTO_THREAD_unlock(global_engine_lock); 253 return ret; 254 } 255 256 ENGINE *ENGINE_get_last(void) 257 { 258 ENGINE *ret; 259 260 if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) { 261 /* Maybe this should be raised in do_engine_lock_init() */ 262 ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); 263 return NULL; 264 } 265 266 if (!CRYPTO_THREAD_write_lock(global_engine_lock)) 267 return NULL; 268 ret = engine_list_tail; 269 if (ret) { 270 int ref; 271 272 if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) { 273 CRYPTO_THREAD_unlock(global_engine_lock); 274 ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); 275 return NULL; 276 } 277 ENGINE_REF_PRINT(ret, 0, 1); 278 } 279 CRYPTO_THREAD_unlock(global_engine_lock); 280 return ret; 281 } 282 283 /* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */ 284 ENGINE *ENGINE_get_next(ENGINE *e) 285 { 286 ENGINE *ret = NULL; 287 if (e == NULL) { 288 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER); 289 return NULL; 290 } 291 if (!CRYPTO_THREAD_write_lock(global_engine_lock)) 292 return NULL; 293 ret = e->next; 294 if (ret) { 295 int ref; 296 297 /* Return a valid structural reference to the next ENGINE */ 298 if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) { 299 CRYPTO_THREAD_unlock(global_engine_lock); 300 ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); 301 return NULL; 302 } 303 ENGINE_REF_PRINT(ret, 0, 1); 304 } 305 CRYPTO_THREAD_unlock(global_engine_lock); 306 /* Release the structural reference to the previous ENGINE */ 307 ENGINE_free(e); 308 return ret; 309 } 310 311 ENGINE *ENGINE_get_prev(ENGINE *e) 312 { 313 ENGINE *ret = NULL; 314 if (e == NULL) { 315 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER); 316 return NULL; 317 } 318 if (!CRYPTO_THREAD_write_lock(global_engine_lock)) 319 return NULL; 320 ret = e->prev; 321 if (ret) { 322 int ref; 323 324 /* Return a valid structural reference to the next ENGINE */ 325 if (!CRYPTO_UP_REF(&ret->struct_ref, &ref)) { 326 CRYPTO_THREAD_unlock(global_engine_lock); 327 ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); 328 return NULL; 329 } 330 ENGINE_REF_PRINT(ret, 0, 1); 331 } 332 CRYPTO_THREAD_unlock(global_engine_lock); 333 /* Release the structural reference to the previous ENGINE */ 334 ENGINE_free(e); 335 return ret; 336 } 337 338 /* Add another "ENGINE" type into the list. */ 339 int ENGINE_add(ENGINE *e) 340 { 341 int to_return = 1; 342 if (e == NULL) { 343 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER); 344 return 0; 345 } 346 if ((e->id == NULL) || (e->name == NULL)) { 347 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_ID_OR_NAME_MISSING); 348 return 0; 349 } 350 if (!CRYPTO_THREAD_write_lock(global_engine_lock)) 351 return 0; 352 if (!engine_list_add(e)) { 353 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR); 354 to_return = 0; 355 } 356 CRYPTO_THREAD_unlock(global_engine_lock); 357 return to_return; 358 } 359 360 /* Remove an existing "ENGINE" type from the array. */ 361 int ENGINE_remove(ENGINE *e) 362 { 363 int to_return = 1; 364 if (e == NULL) { 365 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER); 366 return 0; 367 } 368 if (!CRYPTO_THREAD_write_lock(global_engine_lock)) 369 return 0; 370 if (!engine_list_remove(e)) { 371 ERR_raise(ERR_LIB_ENGINE, ENGINE_R_INTERNAL_LIST_ERROR); 372 to_return = 0; 373 } 374 CRYPTO_THREAD_unlock(global_engine_lock); 375 return to_return; 376 } 377 378 static void engine_cpy(ENGINE *dest, const ENGINE *src) 379 { 380 dest->id = src->id; 381 dest->name = src->name; 382 dest->rsa_meth = src->rsa_meth; 383 #ifndef OPENSSL_NO_DSA 384 dest->dsa_meth = src->dsa_meth; 385 #endif 386 #ifndef OPENSSL_NO_DH 387 dest->dh_meth = src->dh_meth; 388 #endif 389 #ifndef OPENSSL_NO_EC 390 dest->ec_meth = src->ec_meth; 391 #endif 392 dest->rand_meth = src->rand_meth; 393 dest->ciphers = src->ciphers; 394 dest->digests = src->digests; 395 dest->pkey_meths = src->pkey_meths; 396 dest->destroy = src->destroy; 397 dest->init = src->init; 398 dest->finish = src->finish; 399 dest->ctrl = src->ctrl; 400 dest->load_privkey = src->load_privkey; 401 dest->load_pubkey = src->load_pubkey; 402 dest->cmd_defns = src->cmd_defns; 403 dest->flags = src->flags; 404 dest->dynamic_id = src->dynamic_id; 405 engine_add_dynamic_id(dest, NULL, 0); 406 } 407 408 ENGINE *ENGINE_by_id(const char *id) 409 { 410 ENGINE *iterator; 411 const char *load_dir = NULL; 412 if (id == NULL) { 413 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER); 414 return NULL; 415 } 416 ENGINE_load_builtin_engines(); 417 418 if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) { 419 /* Maybe this should be raised in do_engine_lock_init() */ 420 ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); 421 return NULL; 422 } 423 424 if (!CRYPTO_THREAD_write_lock(global_engine_lock)) 425 return NULL; 426 iterator = engine_list_head; 427 while (iterator && (strcmp(id, iterator->id) != 0)) 428 iterator = iterator->next; 429 if (iterator != NULL) { 430 /* 431 * We need to return a structural reference. If this is an ENGINE 432 * type that returns copies, make a duplicate - otherwise increment 433 * the existing ENGINE's reference count. 434 */ 435 if (iterator->flags & ENGINE_FLAGS_BY_ID_COPY) { 436 ENGINE *cp = ENGINE_new(); 437 if (cp == NULL) 438 iterator = NULL; 439 else { 440 engine_cpy(cp, iterator); 441 iterator = cp; 442 } 443 } else { 444 int ref; 445 446 if (!CRYPTO_UP_REF(&iterator->struct_ref, &ref)) { 447 CRYPTO_THREAD_unlock(global_engine_lock); 448 ERR_raise(ERR_LIB_ENGINE, ERR_R_CRYPTO_LIB); 449 return NULL; 450 } 451 ENGINE_REF_PRINT(iterator, 0, 1); 452 } 453 } 454 CRYPTO_THREAD_unlock(global_engine_lock); 455 if (iterator != NULL) 456 return iterator; 457 /* 458 * Prevent infinite recursion if we're looking for the dynamic engine. 459 */ 460 if (strcmp(id, "dynamic")) { 461 if ((load_dir = ossl_safe_getenv("OPENSSL_ENGINES")) == NULL) 462 load_dir = ossl_get_enginesdir(); 463 iterator = ENGINE_by_id("dynamic"); 464 if (!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) || 465 !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) || 466 !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD", 467 load_dir, 0) || 468 !ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) || 469 !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0)) 470 goto notfound; 471 return iterator; 472 } 473 notfound: 474 ENGINE_free(iterator); 475 ERR_raise_data(ERR_LIB_ENGINE, ENGINE_R_NO_SUCH_ENGINE, "id=%s", id); 476 return NULL; 477 /* EEK! Experimental code ends */ 478 } 479 480 int ENGINE_up_ref(ENGINE *e) 481 { 482 int i; 483 if (e == NULL) { 484 ERR_raise(ERR_LIB_ENGINE, ERR_R_PASSED_NULL_PARAMETER); 485 return 0; 486 } 487 CRYPTO_UP_REF(&e->struct_ref, &i); 488 return 1; 489 } 490