1 /* $OpenBSD: eng_list.c,v 1.24 2019/01/19 01:07:00 tb Exp $ */ 2 /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL 3 * project 2000. 4 */ 5 /* ==================================================================== 6 * Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgment: 22 * "This product includes software developed by the OpenSSL Project 23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24 * 25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 * endorse or promote products derived from this software without 27 * prior written permission. For written permission, please contact 28 * licensing@OpenSSL.org. 29 * 30 * 5. Products derived from this software may not be called "OpenSSL" 31 * nor may "OpenSSL" appear in their names without prior written 32 * permission of the OpenSSL Project. 33 * 34 * 6. Redistributions of any form whatsoever must retain the following 35 * acknowledgment: 36 * "This product includes software developed by the OpenSSL Project 37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 * OF THE POSSIBILITY OF SUCH DAMAGE. 51 * ==================================================================== 52 * 53 * This product includes cryptographic software written by Eric Young 54 * (eay@cryptsoft.com). This product includes software written by Tim 55 * Hudson (tjh@cryptsoft.com). 56 * 57 */ 58 /* ==================================================================== 59 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. 60 * ECDH support in OpenSSL originally developed by 61 * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. 62 */ 63 64 #include <string.h> 65 #include <unistd.h> 66 67 #include <openssl/opensslconf.h> 68 69 #include <openssl/err.h> 70 71 #include "cryptlib.h" 72 #include "eng_int.h" 73 74 /* The linked-list of pointers to engine types. engine_list_head 75 * incorporates an implicit structural reference but engine_list_tail 76 * does not - the latter is a computational niceity and only points 77 * to something that is already pointed to by its predecessor in the 78 * list (or engine_list_head itself). In the same way, the use of the 79 * "prev" pointer in each ENGINE is to save excessive list iteration, 80 * it doesn't correspond to an extra structural reference. Hence, 81 * engine_list_head, and each non-null "next" pointer account for 82 * the list itself assuming exactly 1 structural reference on each 83 * list member. */ 84 static ENGINE *engine_list_head = NULL; 85 static ENGINE *engine_list_tail = NULL; 86 87 /* This cleanup function is only needed internally. If it should be called, we 88 * register it with the "ENGINE_cleanup()" stack to be called during cleanup. */ 89 90 static void 91 engine_list_cleanup(void) 92 { 93 ENGINE *iterator = engine_list_head; 94 95 while (iterator != NULL && ENGINE_remove(iterator)) 96 iterator = engine_list_head; 97 } 98 99 /* These static functions starting with a lower case "engine_" always 100 * take place when CRYPTO_LOCK_ENGINE has been locked up. */ 101 static int 102 engine_list_add(ENGINE *e) 103 { 104 int conflict = 0; 105 ENGINE *iterator = NULL; 106 107 if (e == NULL) { 108 ENGINEerror(ERR_R_PASSED_NULL_PARAMETER); 109 return 0; 110 } 111 iterator = engine_list_head; 112 while (iterator && !conflict) { 113 conflict = (strcmp(iterator->id, e->id) == 0); 114 iterator = iterator->next; 115 } 116 if (conflict) { 117 ENGINEerror(ENGINE_R_CONFLICTING_ENGINE_ID); 118 return 0; 119 } 120 if (engine_list_head == NULL) { 121 /* We are adding to an empty list. */ 122 if (engine_list_tail) { 123 ENGINEerror(ENGINE_R_INTERNAL_LIST_ERROR); 124 return 0; 125 } 126 engine_list_head = e; 127 e->prev = NULL; 128 /* The first time the list allocates, we should register the 129 * cleanup. */ 130 engine_cleanup_add_last(engine_list_cleanup); 131 } else { 132 /* We are adding to the tail of an existing list. */ 133 if ((engine_list_tail == NULL) || 134 (engine_list_tail->next != NULL)) { 135 ENGINEerror(ENGINE_R_INTERNAL_LIST_ERROR); 136 return 0; 137 } 138 engine_list_tail->next = e; 139 e->prev = engine_list_tail; 140 } 141 /* Having the engine in the list assumes a structural 142 * reference. */ 143 e->struct_ref++; 144 engine_ref_debug(e, 0, 1) 145 /* However it came to be, e is the last item in the list. */ 146 engine_list_tail = e; 147 e->next = NULL; 148 return 1; 149 } 150 151 static int 152 engine_list_remove(ENGINE *e) 153 { 154 ENGINE *iterator; 155 156 if (e == NULL) { 157 ENGINEerror(ERR_R_PASSED_NULL_PARAMETER); 158 return 0; 159 } 160 /* We need to check that e is in our linked list! */ 161 iterator = engine_list_head; 162 while (iterator && (iterator != e)) 163 iterator = iterator->next; 164 if (iterator == NULL) { 165 ENGINEerror(ENGINE_R_ENGINE_IS_NOT_IN_LIST); 166 return 0; 167 } 168 /* un-link e from the chain. */ 169 if (e->next) 170 e->next->prev = e->prev; 171 if (e->prev) 172 e->prev->next = e->next; 173 /* Correct our head/tail if necessary. */ 174 if (engine_list_head == e) 175 engine_list_head = e->next; 176 if (engine_list_tail == e) 177 engine_list_tail = e->prev; 178 engine_free_util(e, 0); 179 return 1; 180 } 181 182 /* Get the first/last "ENGINE" type available. */ 183 ENGINE * 184 ENGINE_get_first(void) 185 { 186 ENGINE *ret; 187 188 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 189 ret = engine_list_head; 190 if (ret) { 191 ret->struct_ref++; 192 engine_ref_debug(ret, 0, 1) 193 } 194 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 195 return ret; 196 } 197 198 ENGINE * 199 ENGINE_get_last(void) 200 { 201 ENGINE *ret; 202 203 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 204 ret = engine_list_tail; 205 if (ret) { 206 ret->struct_ref++; 207 engine_ref_debug(ret, 0, 1) 208 } 209 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 210 return ret; 211 } 212 213 /* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */ 214 ENGINE * 215 ENGINE_get_next(ENGINE *e) 216 { 217 ENGINE *ret = NULL; 218 219 if (e == NULL) { 220 ENGINEerror(ERR_R_PASSED_NULL_PARAMETER); 221 return 0; 222 } 223 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 224 ret = e->next; 225 if (ret) { 226 /* Return a valid structural refernce to the next ENGINE */ 227 ret->struct_ref++; 228 engine_ref_debug(ret, 0, 1) 229 } 230 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 231 /* Release the structural reference to the previous ENGINE */ 232 ENGINE_free(e); 233 return ret; 234 } 235 236 ENGINE * 237 ENGINE_get_prev(ENGINE *e) 238 { 239 ENGINE *ret = NULL; 240 241 if (e == NULL) { 242 ENGINEerror(ERR_R_PASSED_NULL_PARAMETER); 243 return 0; 244 } 245 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 246 ret = e->prev; 247 if (ret) { 248 /* Return a valid structural reference to the next ENGINE */ 249 ret->struct_ref++; 250 engine_ref_debug(ret, 0, 1) 251 } 252 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 253 /* Release the structural reference to the previous ENGINE */ 254 ENGINE_free(e); 255 return ret; 256 } 257 258 /* Add another "ENGINE" type into the list. */ 259 int 260 ENGINE_add(ENGINE *e) 261 { 262 int to_return = 1; 263 264 if (e == NULL) { 265 ENGINEerror(ERR_R_PASSED_NULL_PARAMETER); 266 return 0; 267 } 268 if ((e->id == NULL) || (e->name == NULL)) { 269 ENGINEerror(ENGINE_R_ID_OR_NAME_MISSING); 270 } 271 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 272 if (!engine_list_add(e)) { 273 ENGINEerror(ENGINE_R_INTERNAL_LIST_ERROR); 274 to_return = 0; 275 } 276 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 277 return to_return; 278 } 279 280 /* Remove an existing "ENGINE" type from the array. */ 281 int 282 ENGINE_remove(ENGINE *e) 283 { 284 int to_return = 1; 285 286 if (e == NULL) { 287 ENGINEerror(ERR_R_PASSED_NULL_PARAMETER); 288 return 0; 289 } 290 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 291 if (!engine_list_remove(e)) { 292 ENGINEerror(ENGINE_R_INTERNAL_LIST_ERROR); 293 to_return = 0; 294 } 295 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 296 return to_return; 297 } 298 299 static void 300 engine_cpy(ENGINE *dest, const ENGINE *src) 301 { 302 dest->id = src->id; 303 dest->name = src->name; 304 #ifndef OPENSSL_NO_RSA 305 dest->rsa_meth = src->rsa_meth; 306 #endif 307 #ifndef OPENSSL_NO_DSA 308 dest->dsa_meth = src->dsa_meth; 309 #endif 310 #ifndef OPENSSL_NO_DH 311 dest->dh_meth = src->dh_meth; 312 #endif 313 #ifndef OPENSSL_NO_ECDH 314 dest->ecdh_meth = src->ecdh_meth; 315 #endif 316 #ifndef OPENSSL_NO_ECDSA 317 dest->ecdsa_meth = src->ecdsa_meth; 318 #endif 319 #ifndef OPENSSL_NO_EC 320 dest->ec_meth = src->ec_meth; 321 #endif 322 dest->rand_meth = src->rand_meth; 323 dest->store_meth = src->store_meth; 324 dest->ciphers = src->ciphers; 325 dest->digests = src->digests; 326 dest->pkey_meths = src->pkey_meths; 327 dest->destroy = src->destroy; 328 dest->init = src->init; 329 dest->finish = src->finish; 330 dest->ctrl = src->ctrl; 331 dest->load_privkey = src->load_privkey; 332 dest->load_pubkey = src->load_pubkey; 333 dest->cmd_defns = src->cmd_defns; 334 dest->flags = src->flags; 335 } 336 337 ENGINE * 338 ENGINE_by_id(const char *id) 339 { 340 ENGINE *iterator; 341 342 if (id == NULL) { 343 ENGINEerror(ERR_R_PASSED_NULL_PARAMETER); 344 return NULL; 345 } 346 CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 347 iterator = engine_list_head; 348 while (iterator && (strcmp(id, iterator->id) != 0)) 349 iterator = iterator->next; 350 if (iterator) { 351 /* We need to return a structural reference. If this is an 352 * ENGINE type that returns copies, make a duplicate - otherwise 353 * increment the existing ENGINE's reference count. */ 354 if (iterator->flags & ENGINE_FLAGS_BY_ID_COPY) { 355 ENGINE *cp = ENGINE_new(); 356 if (!cp) 357 iterator = NULL; 358 else { 359 engine_cpy(cp, iterator); 360 iterator = cp; 361 } 362 } else { 363 iterator->struct_ref++; 364 engine_ref_debug(iterator, 0, 1) 365 } 366 } 367 CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 368 369 if (iterator == NULL) { 370 ENGINEerror(ENGINE_R_NO_SUCH_ENGINE); 371 ERR_asprintf_error_data("id=%s", id); 372 } 373 return iterator; 374 } 375 376 int 377 ENGINE_up_ref(ENGINE *e) 378 { 379 int refs; 380 381 if (e == NULL) { 382 ENGINEerror(ERR_R_PASSED_NULL_PARAMETER); 383 return 0; 384 } 385 refs = CRYPTO_add(&e->struct_ref, 1, CRYPTO_LOCK_ENGINE); 386 return refs > 1 ? 1 : 0; 387 } 388