1109998Smarkm/* crypto/engine/eng_list.c */ 2109998Smarkm/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL 3109998Smarkm * project 2000. 4109998Smarkm */ 5109998Smarkm/* ==================================================================== 6109998Smarkm * Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved. 7109998Smarkm * 8109998Smarkm * Redistribution and use in source and binary forms, with or without 9109998Smarkm * modification, are permitted provided that the following conditions 10109998Smarkm * are met: 11109998Smarkm * 12109998Smarkm * 1. Redistributions of source code must retain the above copyright 13109998Smarkm * notice, this list of conditions and the following disclaimer. 14109998Smarkm * 15109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 16109998Smarkm * notice, this list of conditions and the following disclaimer in 17109998Smarkm * the documentation and/or other materials provided with the 18109998Smarkm * distribution. 19109998Smarkm * 20109998Smarkm * 3. All advertising materials mentioning features or use of this 21109998Smarkm * software must display the following acknowledgment: 22109998Smarkm * "This product includes software developed by the OpenSSL Project 23109998Smarkm * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24109998Smarkm * 25109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26109998Smarkm * endorse or promote products derived from this software without 27109998Smarkm * prior written permission. For written permission, please contact 28109998Smarkm * licensing@OpenSSL.org. 29109998Smarkm * 30109998Smarkm * 5. Products derived from this software may not be called "OpenSSL" 31109998Smarkm * nor may "OpenSSL" appear in their names without prior written 32109998Smarkm * permission of the OpenSSL Project. 33109998Smarkm * 34109998Smarkm * 6. Redistributions of any form whatsoever must retain the following 35109998Smarkm * acknowledgment: 36109998Smarkm * "This product includes software developed by the OpenSSL Project 37109998Smarkm * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38109998Smarkm * 39109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42109998Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE. 51109998Smarkm * ==================================================================== 52109998Smarkm * 53109998Smarkm * This product includes cryptographic software written by Eric Young 54109998Smarkm * (eay@cryptsoft.com). This product includes software written by Tim 55109998Smarkm * Hudson (tjh@cryptsoft.com). 56109998Smarkm * 57109998Smarkm */ 58160814Ssimon/* ==================================================================== 59160814Ssimon * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. 60160814Ssimon * ECDH support in OpenSSL originally developed by 61160814Ssimon * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. 62160814Ssimon */ 63109998Smarkm 64109998Smarkm#include "eng_int.h" 65109998Smarkm 66109998Smarkm/* The linked-list of pointers to engine types. engine_list_head 67109998Smarkm * incorporates an implicit structural reference but engine_list_tail 68109998Smarkm * does not - the latter is a computational niceity and only points 69109998Smarkm * to something that is already pointed to by its predecessor in the 70109998Smarkm * list (or engine_list_head itself). In the same way, the use of the 71109998Smarkm * "prev" pointer in each ENGINE is to save excessive list iteration, 72109998Smarkm * it doesn't correspond to an extra structural reference. Hence, 73109998Smarkm * engine_list_head, and each non-null "next" pointer account for 74109998Smarkm * the list itself assuming exactly 1 structural reference on each 75109998Smarkm * list member. */ 76109998Smarkmstatic ENGINE *engine_list_head = NULL; 77109998Smarkmstatic ENGINE *engine_list_tail = NULL; 78109998Smarkm 79109998Smarkm/* This cleanup function is only needed internally. If it should be called, we 80109998Smarkm * register it with the "ENGINE_cleanup()" stack to be called during cleanup. */ 81109998Smarkm 82109998Smarkmstatic void engine_list_cleanup(void) 83109998Smarkm { 84109998Smarkm ENGINE *iterator = engine_list_head; 85109998Smarkm 86109998Smarkm while(iterator != NULL) 87109998Smarkm { 88109998Smarkm ENGINE_remove(iterator); 89109998Smarkm iterator = engine_list_head; 90109998Smarkm } 91109998Smarkm return; 92109998Smarkm } 93109998Smarkm 94109998Smarkm/* These static functions starting with a lower case "engine_" always 95109998Smarkm * take place when CRYPTO_LOCK_ENGINE has been locked up. */ 96109998Smarkmstatic int engine_list_add(ENGINE *e) 97109998Smarkm { 98109998Smarkm int conflict = 0; 99109998Smarkm ENGINE *iterator = NULL; 100109998Smarkm 101109998Smarkm if(e == NULL) 102109998Smarkm { 103109998Smarkm ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, 104109998Smarkm ERR_R_PASSED_NULL_PARAMETER); 105109998Smarkm return 0; 106109998Smarkm } 107109998Smarkm iterator = engine_list_head; 108109998Smarkm while(iterator && !conflict) 109109998Smarkm { 110109998Smarkm conflict = (strcmp(iterator->id, e->id) == 0); 111109998Smarkm iterator = iterator->next; 112109998Smarkm } 113109998Smarkm if(conflict) 114109998Smarkm { 115109998Smarkm ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, 116109998Smarkm ENGINE_R_CONFLICTING_ENGINE_ID); 117109998Smarkm return 0; 118109998Smarkm } 119109998Smarkm if(engine_list_head == NULL) 120109998Smarkm { 121109998Smarkm /* We are adding to an empty list. */ 122109998Smarkm if(engine_list_tail) 123109998Smarkm { 124109998Smarkm ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, 125109998Smarkm ENGINE_R_INTERNAL_LIST_ERROR); 126109998Smarkm return 0; 127109998Smarkm } 128109998Smarkm engine_list_head = e; 129109998Smarkm e->prev = NULL; 130109998Smarkm /* The first time the list allocates, we should register the 131109998Smarkm * cleanup. */ 132109998Smarkm engine_cleanup_add_last(engine_list_cleanup); 133109998Smarkm } 134109998Smarkm else 135109998Smarkm { 136109998Smarkm /* We are adding to the tail of an existing list. */ 137109998Smarkm if((engine_list_tail == NULL) || 138109998Smarkm (engine_list_tail->next != NULL)) 139109998Smarkm { 140109998Smarkm ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, 141109998Smarkm ENGINE_R_INTERNAL_LIST_ERROR); 142109998Smarkm return 0; 143109998Smarkm } 144109998Smarkm engine_list_tail->next = e; 145109998Smarkm e->prev = engine_list_tail; 146109998Smarkm } 147109998Smarkm /* Having the engine in the list assumes a structural 148109998Smarkm * reference. */ 149109998Smarkm e->struct_ref++; 150109998Smarkm engine_ref_debug(e, 0, 1) 151109998Smarkm /* However it came to be, e is the last item in the list. */ 152109998Smarkm engine_list_tail = e; 153109998Smarkm e->next = NULL; 154109998Smarkm return 1; 155109998Smarkm } 156109998Smarkm 157109998Smarkmstatic int engine_list_remove(ENGINE *e) 158109998Smarkm { 159109998Smarkm ENGINE *iterator; 160109998Smarkm 161109998Smarkm if(e == NULL) 162109998Smarkm { 163109998Smarkm ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE, 164109998Smarkm ERR_R_PASSED_NULL_PARAMETER); 165109998Smarkm return 0; 166109998Smarkm } 167109998Smarkm /* We need to check that e is in our linked list! */ 168109998Smarkm iterator = engine_list_head; 169109998Smarkm while(iterator && (iterator != e)) 170109998Smarkm iterator = iterator->next; 171109998Smarkm if(iterator == NULL) 172109998Smarkm { 173109998Smarkm ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE, 174109998Smarkm ENGINE_R_ENGINE_IS_NOT_IN_LIST); 175109998Smarkm return 0; 176109998Smarkm } 177109998Smarkm /* un-link e from the chain. */ 178109998Smarkm if(e->next) 179109998Smarkm e->next->prev = e->prev; 180109998Smarkm if(e->prev) 181109998Smarkm e->prev->next = e->next; 182109998Smarkm /* Correct our head/tail if necessary. */ 183109998Smarkm if(engine_list_head == e) 184109998Smarkm engine_list_head = e->next; 185109998Smarkm if(engine_list_tail == e) 186109998Smarkm engine_list_tail = e->prev; 187109998Smarkm engine_free_util(e, 0); 188109998Smarkm return 1; 189109998Smarkm } 190109998Smarkm 191109998Smarkm/* Get the first/last "ENGINE" type available. */ 192109998SmarkmENGINE *ENGINE_get_first(void) 193109998Smarkm { 194109998Smarkm ENGINE *ret; 195109998Smarkm 196109998Smarkm CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 197109998Smarkm ret = engine_list_head; 198109998Smarkm if(ret) 199109998Smarkm { 200109998Smarkm ret->struct_ref++; 201109998Smarkm engine_ref_debug(ret, 0, 1) 202109998Smarkm } 203109998Smarkm CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 204109998Smarkm return ret; 205109998Smarkm } 206109998Smarkm 207109998SmarkmENGINE *ENGINE_get_last(void) 208109998Smarkm { 209109998Smarkm ENGINE *ret; 210109998Smarkm 211109998Smarkm CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 212109998Smarkm ret = engine_list_tail; 213109998Smarkm if(ret) 214109998Smarkm { 215109998Smarkm ret->struct_ref++; 216109998Smarkm engine_ref_debug(ret, 0, 1) 217109998Smarkm } 218109998Smarkm CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 219109998Smarkm return ret; 220109998Smarkm } 221109998Smarkm 222109998Smarkm/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */ 223109998SmarkmENGINE *ENGINE_get_next(ENGINE *e) 224109998Smarkm { 225109998Smarkm ENGINE *ret = NULL; 226109998Smarkm if(e == NULL) 227109998Smarkm { 228109998Smarkm ENGINEerr(ENGINE_F_ENGINE_GET_NEXT, 229109998Smarkm ERR_R_PASSED_NULL_PARAMETER); 230109998Smarkm return 0; 231109998Smarkm } 232109998Smarkm CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 233109998Smarkm ret = e->next; 234109998Smarkm if(ret) 235109998Smarkm { 236109998Smarkm /* Return a valid structural refernce to the next ENGINE */ 237109998Smarkm ret->struct_ref++; 238109998Smarkm engine_ref_debug(ret, 0, 1) 239109998Smarkm } 240109998Smarkm CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 241109998Smarkm /* Release the structural reference to the previous ENGINE */ 242109998Smarkm ENGINE_free(e); 243109998Smarkm return ret; 244109998Smarkm } 245109998Smarkm 246109998SmarkmENGINE *ENGINE_get_prev(ENGINE *e) 247109998Smarkm { 248109998Smarkm ENGINE *ret = NULL; 249109998Smarkm if(e == NULL) 250109998Smarkm { 251109998Smarkm ENGINEerr(ENGINE_F_ENGINE_GET_PREV, 252109998Smarkm ERR_R_PASSED_NULL_PARAMETER); 253109998Smarkm return 0; 254109998Smarkm } 255109998Smarkm CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 256109998Smarkm ret = e->prev; 257109998Smarkm if(ret) 258109998Smarkm { 259109998Smarkm /* Return a valid structural reference to the next ENGINE */ 260109998Smarkm ret->struct_ref++; 261109998Smarkm engine_ref_debug(ret, 0, 1) 262109998Smarkm } 263109998Smarkm CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 264109998Smarkm /* Release the structural reference to the previous ENGINE */ 265109998Smarkm ENGINE_free(e); 266109998Smarkm return ret; 267109998Smarkm } 268109998Smarkm 269109998Smarkm/* Add another "ENGINE" type into the list. */ 270109998Smarkmint ENGINE_add(ENGINE *e) 271109998Smarkm { 272109998Smarkm int to_return = 1; 273109998Smarkm if(e == NULL) 274109998Smarkm { 275109998Smarkm ENGINEerr(ENGINE_F_ENGINE_ADD, 276109998Smarkm ERR_R_PASSED_NULL_PARAMETER); 277109998Smarkm return 0; 278109998Smarkm } 279109998Smarkm if((e->id == NULL) || (e->name == NULL)) 280109998Smarkm { 281109998Smarkm ENGINEerr(ENGINE_F_ENGINE_ADD, 282109998Smarkm ENGINE_R_ID_OR_NAME_MISSING); 283109998Smarkm } 284109998Smarkm CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 285109998Smarkm if(!engine_list_add(e)) 286109998Smarkm { 287109998Smarkm ENGINEerr(ENGINE_F_ENGINE_ADD, 288109998Smarkm ENGINE_R_INTERNAL_LIST_ERROR); 289109998Smarkm to_return = 0; 290109998Smarkm } 291109998Smarkm CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 292109998Smarkm return to_return; 293109998Smarkm } 294109998Smarkm 295109998Smarkm/* Remove an existing "ENGINE" type from the array. */ 296109998Smarkmint ENGINE_remove(ENGINE *e) 297109998Smarkm { 298109998Smarkm int to_return = 1; 299109998Smarkm if(e == NULL) 300109998Smarkm { 301109998Smarkm ENGINEerr(ENGINE_F_ENGINE_REMOVE, 302109998Smarkm ERR_R_PASSED_NULL_PARAMETER); 303109998Smarkm return 0; 304109998Smarkm } 305109998Smarkm CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 306109998Smarkm if(!engine_list_remove(e)) 307109998Smarkm { 308109998Smarkm ENGINEerr(ENGINE_F_ENGINE_REMOVE, 309109998Smarkm ENGINE_R_INTERNAL_LIST_ERROR); 310109998Smarkm to_return = 0; 311109998Smarkm } 312109998Smarkm CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 313109998Smarkm return to_return; 314109998Smarkm } 315109998Smarkm 316109998Smarkmstatic void engine_cpy(ENGINE *dest, const ENGINE *src) 317109998Smarkm { 318109998Smarkm dest->id = src->id; 319109998Smarkm dest->name = src->name; 320109998Smarkm#ifndef OPENSSL_NO_RSA 321109998Smarkm dest->rsa_meth = src->rsa_meth; 322109998Smarkm#endif 323109998Smarkm#ifndef OPENSSL_NO_DSA 324109998Smarkm dest->dsa_meth = src->dsa_meth; 325109998Smarkm#endif 326109998Smarkm#ifndef OPENSSL_NO_DH 327109998Smarkm dest->dh_meth = src->dh_meth; 328109998Smarkm#endif 329160814Ssimon#ifndef OPENSSL_NO_ECDH 330160814Ssimon dest->ecdh_meth = src->ecdh_meth; 331160814Ssimon#endif 332160814Ssimon#ifndef OPENSSL_NO_ECDSA 333160814Ssimon dest->ecdsa_meth = src->ecdsa_meth; 334160814Ssimon#endif 335109998Smarkm dest->rand_meth = src->rand_meth; 336160814Ssimon dest->store_meth = src->store_meth; 337109998Smarkm dest->ciphers = src->ciphers; 338109998Smarkm dest->digests = src->digests; 339238405Sjkim dest->pkey_meths = src->pkey_meths; 340109998Smarkm dest->destroy = src->destroy; 341109998Smarkm dest->init = src->init; 342109998Smarkm dest->finish = src->finish; 343109998Smarkm dest->ctrl = src->ctrl; 344109998Smarkm dest->load_privkey = src->load_privkey; 345109998Smarkm dest->load_pubkey = src->load_pubkey; 346109998Smarkm dest->cmd_defns = src->cmd_defns; 347109998Smarkm dest->flags = src->flags; 348109998Smarkm } 349109998Smarkm 350109998SmarkmENGINE *ENGINE_by_id(const char *id) 351109998Smarkm { 352109998Smarkm ENGINE *iterator; 353160814Ssimon char *load_dir = NULL; 354109998Smarkm if(id == NULL) 355109998Smarkm { 356109998Smarkm ENGINEerr(ENGINE_F_ENGINE_BY_ID, 357109998Smarkm ERR_R_PASSED_NULL_PARAMETER); 358109998Smarkm return NULL; 359109998Smarkm } 360109998Smarkm CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 361109998Smarkm iterator = engine_list_head; 362109998Smarkm while(iterator && (strcmp(id, iterator->id) != 0)) 363109998Smarkm iterator = iterator->next; 364109998Smarkm if(iterator) 365109998Smarkm { 366109998Smarkm /* We need to return a structural reference. If this is an 367109998Smarkm * ENGINE type that returns copies, make a duplicate - otherwise 368109998Smarkm * increment the existing ENGINE's reference count. */ 369109998Smarkm if(iterator->flags & ENGINE_FLAGS_BY_ID_COPY) 370109998Smarkm { 371109998Smarkm ENGINE *cp = ENGINE_new(); 372109998Smarkm if(!cp) 373109998Smarkm iterator = NULL; 374109998Smarkm else 375109998Smarkm { 376109998Smarkm engine_cpy(cp, iterator); 377109998Smarkm iterator = cp; 378109998Smarkm } 379109998Smarkm } 380109998Smarkm else 381109998Smarkm { 382109998Smarkm iterator->struct_ref++; 383109998Smarkm engine_ref_debug(iterator, 0, 1) 384109998Smarkm } 385109998Smarkm } 386109998Smarkm CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 387160814Ssimon#if 0 388109998Smarkm if(iterator == NULL) 389109998Smarkm { 390109998Smarkm ENGINEerr(ENGINE_F_ENGINE_BY_ID, 391109998Smarkm ENGINE_R_NO_SUCH_ENGINE); 392109998Smarkm ERR_add_error_data(2, "id=", id); 393109998Smarkm } 394109998Smarkm return iterator; 395160814Ssimon#else 396160814Ssimon /* EEK! Experimental code starts */ 397160814Ssimon if(iterator) return iterator; 398160814Ssimon /* Prevent infinite recusrion if we're looking for the dynamic engine. */ 399160814Ssimon if (strcmp(id, "dynamic")) 400160814Ssimon { 401160814Ssimon#ifdef OPENSSL_SYS_VMS 402160814Ssimon if((load_dir = getenv("OPENSSL_ENGINES")) == 0) load_dir = "SSLROOT:[ENGINES]"; 403160814Ssimon#else 404160814Ssimon if((load_dir = getenv("OPENSSL_ENGINES")) == 0) load_dir = ENGINESDIR; 405160814Ssimon#endif 406160814Ssimon iterator = ENGINE_by_id("dynamic"); 407160814Ssimon if(!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) || 408160814Ssimon !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) || 409160814Ssimon !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD", 410160814Ssimon load_dir, 0) || 411279264Sdelphij !ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) || 412160814Ssimon !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0)) 413160814Ssimon goto notfound; 414160814Ssimon return iterator; 415160814Ssimon } 416160814Ssimonnotfound: 417215697Ssimon ENGINE_free(iterator); 418160814Ssimon ENGINEerr(ENGINE_F_ENGINE_BY_ID,ENGINE_R_NO_SUCH_ENGINE); 419160814Ssimon ERR_add_error_data(2, "id=", id); 420160814Ssimon return NULL; 421160814Ssimon /* EEK! Experimental code ends */ 422160814Ssimon#endif 423109998Smarkm } 424109998Smarkm 425109998Smarkmint ENGINE_up_ref(ENGINE *e) 426109998Smarkm { 427109998Smarkm if (e == NULL) 428109998Smarkm { 429109998Smarkm ENGINEerr(ENGINE_F_ENGINE_UP_REF,ERR_R_PASSED_NULL_PARAMETER); 430109998Smarkm return 0; 431109998Smarkm } 432109998Smarkm CRYPTO_add(&e->struct_ref,1,CRYPTO_LOCK_ENGINE); 433109998Smarkm return 1; 434109998Smarkm } 435