1109998Smarkm/* crypto/engine/eng_list.c */ 2296341Sdelphij/* 3296341Sdelphij * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project 4296341Sdelphij * 2000. 5109998Smarkm */ 6109998Smarkm/* ==================================================================== 7109998Smarkm * Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved. 8109998Smarkm * 9109998Smarkm * Redistribution and use in source and binary forms, with or without 10109998Smarkm * modification, are permitted provided that the following conditions 11109998Smarkm * are met: 12109998Smarkm * 13109998Smarkm * 1. Redistributions of source code must retain the above copyright 14296341Sdelphij * notice, this list of conditions and the following disclaimer. 15109998Smarkm * 16109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 17109998Smarkm * notice, this list of conditions and the following disclaimer in 18109998Smarkm * the documentation and/or other materials provided with the 19109998Smarkm * distribution. 20109998Smarkm * 21109998Smarkm * 3. All advertising materials mentioning features or use of this 22109998Smarkm * software must display the following acknowledgment: 23109998Smarkm * "This product includes software developed by the OpenSSL Project 24109998Smarkm * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25109998Smarkm * 26109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27109998Smarkm * endorse or promote products derived from this software without 28109998Smarkm * prior written permission. For written permission, please contact 29109998Smarkm * licensing@OpenSSL.org. 30109998Smarkm * 31109998Smarkm * 5. Products derived from this software may not be called "OpenSSL" 32109998Smarkm * nor may "OpenSSL" appear in their names without prior written 33109998Smarkm * permission of the OpenSSL Project. 34109998Smarkm * 35109998Smarkm * 6. Redistributions of any form whatsoever must retain the following 36109998Smarkm * acknowledgment: 37109998Smarkm * "This product includes software developed by the OpenSSL Project 38109998Smarkm * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39109998Smarkm * 40109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43109998Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE. 52109998Smarkm * ==================================================================== 53109998Smarkm * 54109998Smarkm * This product includes cryptographic software written by Eric Young 55109998Smarkm * (eay@cryptsoft.com). This product includes software written by Tim 56109998Smarkm * Hudson (tjh@cryptsoft.com). 57109998Smarkm * 58109998Smarkm */ 59160814Ssimon/* ==================================================================== 60160814Ssimon * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. 61296341Sdelphij * ECDH support in OpenSSL originally developed by 62160814Ssimon * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. 63160814Ssimon */ 64109998Smarkm 65109998Smarkm#include "eng_int.h" 66109998Smarkm 67296341Sdelphij/* 68296341Sdelphij * The linked-list of pointers to engine types. engine_list_head incorporates 69296341Sdelphij * an implicit structural reference but engine_list_tail does not - the 70296341Sdelphij * latter is a computational niceity and only points to something that is 71296341Sdelphij * already pointed to by its predecessor in the list (or engine_list_head 72296341Sdelphij * itself). In the same way, the use of the "prev" pointer in each ENGINE is 73296341Sdelphij * to save excessive list iteration, it doesn't correspond to an extra 74296341Sdelphij * structural reference. Hence, engine_list_head, and each non-null "next" 75296341Sdelphij * pointer account for the list itself assuming exactly 1 structural 76296341Sdelphij * reference on each list member. 77296341Sdelphij */ 78109998Smarkmstatic ENGINE *engine_list_head = NULL; 79109998Smarkmstatic ENGINE *engine_list_tail = NULL; 80109998Smarkm 81296341Sdelphij/* 82296341Sdelphij * This cleanup function is only needed internally. If it should be called, 83296341Sdelphij * we register it with the "ENGINE_cleanup()" stack to be called during 84296341Sdelphij * cleanup. 85296341Sdelphij */ 86109998Smarkm 87109998Smarkmstatic void engine_list_cleanup(void) 88296341Sdelphij{ 89296341Sdelphij ENGINE *iterator = engine_list_head; 90109998Smarkm 91296341Sdelphij while (iterator != NULL) { 92296341Sdelphij ENGINE_remove(iterator); 93296341Sdelphij iterator = engine_list_head; 94296341Sdelphij } 95296341Sdelphij return; 96296341Sdelphij} 97109998Smarkm 98296341Sdelphij/* 99296341Sdelphij * These static functions starting with a lower case "engine_" always take 100296341Sdelphij * place when CRYPTO_LOCK_ENGINE has been locked up. 101296341Sdelphij */ 102109998Smarkmstatic int engine_list_add(ENGINE *e) 103296341Sdelphij{ 104296341Sdelphij int conflict = 0; 105296341Sdelphij ENGINE *iterator = NULL; 106109998Smarkm 107296341Sdelphij if (e == NULL) { 108296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, ERR_R_PASSED_NULL_PARAMETER); 109296341Sdelphij return 0; 110296341Sdelphij } 111296341Sdelphij iterator = engine_list_head; 112296341Sdelphij while (iterator && !conflict) { 113296341Sdelphij conflict = (strcmp(iterator->id, e->id) == 0); 114296341Sdelphij iterator = iterator->next; 115296341Sdelphij } 116296341Sdelphij if (conflict) { 117296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, ENGINE_R_CONFLICTING_ENGINE_ID); 118296341Sdelphij return 0; 119296341Sdelphij } 120296341Sdelphij if (engine_list_head == NULL) { 121296341Sdelphij /* We are adding to an empty list. */ 122296341Sdelphij if (engine_list_tail) { 123296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, ENGINE_R_INTERNAL_LIST_ERROR); 124296341Sdelphij return 0; 125296341Sdelphij } 126296341Sdelphij engine_list_head = e; 127296341Sdelphij e->prev = NULL; 128296341Sdelphij /* 129296341Sdelphij * The first time the list allocates, we should register the cleanup. 130296341Sdelphij */ 131296341Sdelphij engine_cleanup_add_last(engine_list_cleanup); 132296341Sdelphij } else { 133296341Sdelphij /* We are adding to the tail of an existing list. */ 134296341Sdelphij if ((engine_list_tail == NULL) || (engine_list_tail->next != NULL)) { 135296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_LIST_ADD, ENGINE_R_INTERNAL_LIST_ERROR); 136296341Sdelphij return 0; 137296341Sdelphij } 138296341Sdelphij engine_list_tail->next = e; 139296341Sdelphij e->prev = engine_list_tail; 140296341Sdelphij } 141296341Sdelphij /* 142296341Sdelphij * Having the engine in the list assumes a structural reference. 143296341Sdelphij */ 144296341Sdelphij e->struct_ref++; 145296341Sdelphij engine_ref_debug(e, 0, 1) 146296341Sdelphij /* However it came to be, e is the last item in the list. */ 147296341Sdelphij engine_list_tail = e; 148296341Sdelphij e->next = NULL; 149296341Sdelphij return 1; 150296341Sdelphij} 151109998Smarkm 152109998Smarkmstatic int engine_list_remove(ENGINE *e) 153296341Sdelphij{ 154296341Sdelphij ENGINE *iterator; 155109998Smarkm 156296341Sdelphij if (e == NULL) { 157296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE, ERR_R_PASSED_NULL_PARAMETER); 158296341Sdelphij return 0; 159296341Sdelphij } 160296341Sdelphij /* We need to check that e is in our linked list! */ 161296341Sdelphij iterator = engine_list_head; 162296341Sdelphij while (iterator && (iterator != e)) 163296341Sdelphij iterator = iterator->next; 164296341Sdelphij if (iterator == NULL) { 165296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE, 166296341Sdelphij ENGINE_R_ENGINE_IS_NOT_IN_LIST); 167296341Sdelphij return 0; 168296341Sdelphij } 169296341Sdelphij /* un-link e from the chain. */ 170296341Sdelphij if (e->next) 171296341Sdelphij e->next->prev = e->prev; 172296341Sdelphij if (e->prev) 173296341Sdelphij e->prev->next = e->next; 174296341Sdelphij /* Correct our head/tail if necessary. */ 175296341Sdelphij if (engine_list_head == e) 176296341Sdelphij engine_list_head = e->next; 177296341Sdelphij if (engine_list_tail == e) 178296341Sdelphij engine_list_tail = e->prev; 179296341Sdelphij engine_free_util(e, 0); 180296341Sdelphij return 1; 181296341Sdelphij} 182109998Smarkm 183109998Smarkm/* Get the first/last "ENGINE" type available. */ 184109998SmarkmENGINE *ENGINE_get_first(void) 185296341Sdelphij{ 186296341Sdelphij ENGINE *ret; 187109998Smarkm 188296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 189296341Sdelphij ret = engine_list_head; 190296341Sdelphij if (ret) { 191296341Sdelphij ret->struct_ref++; 192296341Sdelphij engine_ref_debug(ret, 0, 1) 193296341Sdelphij } 194296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 195296341Sdelphij return ret; 196296341Sdelphij} 197109998Smarkm 198109998SmarkmENGINE *ENGINE_get_last(void) 199296341Sdelphij{ 200296341Sdelphij ENGINE *ret; 201109998Smarkm 202296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 203296341Sdelphij ret = engine_list_tail; 204296341Sdelphij if (ret) { 205296341Sdelphij ret->struct_ref++; 206296341Sdelphij engine_ref_debug(ret, 0, 1) 207296341Sdelphij } 208296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 209296341Sdelphij return ret; 210296341Sdelphij} 211109998Smarkm 212109998Smarkm/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */ 213109998SmarkmENGINE *ENGINE_get_next(ENGINE *e) 214296341Sdelphij{ 215296341Sdelphij ENGINE *ret = NULL; 216296341Sdelphij if (e == NULL) { 217296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_GET_NEXT, ERR_R_PASSED_NULL_PARAMETER); 218296341Sdelphij return 0; 219296341Sdelphij } 220296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 221296341Sdelphij ret = e->next; 222296341Sdelphij if (ret) { 223296341Sdelphij /* Return a valid structural refernce to the next ENGINE */ 224296341Sdelphij ret->struct_ref++; 225296341Sdelphij engine_ref_debug(ret, 0, 1) 226296341Sdelphij } 227296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 228296341Sdelphij /* Release the structural reference to the previous ENGINE */ 229296341Sdelphij ENGINE_free(e); 230296341Sdelphij return ret; 231296341Sdelphij} 232109998Smarkm 233109998SmarkmENGINE *ENGINE_get_prev(ENGINE *e) 234296341Sdelphij{ 235296341Sdelphij ENGINE *ret = NULL; 236296341Sdelphij if (e == NULL) { 237296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_GET_PREV, ERR_R_PASSED_NULL_PARAMETER); 238296341Sdelphij return 0; 239296341Sdelphij } 240296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 241296341Sdelphij ret = e->prev; 242296341Sdelphij if (ret) { 243296341Sdelphij /* Return a valid structural reference to the next ENGINE */ 244296341Sdelphij ret->struct_ref++; 245296341Sdelphij engine_ref_debug(ret, 0, 1) 246296341Sdelphij } 247296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 248296341Sdelphij /* Release the structural reference to the previous ENGINE */ 249296341Sdelphij ENGINE_free(e); 250296341Sdelphij return ret; 251296341Sdelphij} 252109998Smarkm 253109998Smarkm/* Add another "ENGINE" type into the list. */ 254109998Smarkmint ENGINE_add(ENGINE *e) 255296341Sdelphij{ 256296341Sdelphij int to_return = 1; 257296341Sdelphij if (e == NULL) { 258296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_ADD, ERR_R_PASSED_NULL_PARAMETER); 259296341Sdelphij return 0; 260296341Sdelphij } 261296341Sdelphij if ((e->id == NULL) || (e->name == NULL)) { 262296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_ADD, ENGINE_R_ID_OR_NAME_MISSING); 263296341Sdelphij } 264296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 265296341Sdelphij if (!engine_list_add(e)) { 266296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_ADD, ENGINE_R_INTERNAL_LIST_ERROR); 267296341Sdelphij to_return = 0; 268296341Sdelphij } 269296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 270296341Sdelphij return to_return; 271296341Sdelphij} 272109998Smarkm 273109998Smarkm/* Remove an existing "ENGINE" type from the array. */ 274109998Smarkmint ENGINE_remove(ENGINE *e) 275296341Sdelphij{ 276296341Sdelphij int to_return = 1; 277296341Sdelphij if (e == NULL) { 278296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_REMOVE, ERR_R_PASSED_NULL_PARAMETER); 279296341Sdelphij return 0; 280296341Sdelphij } 281296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 282296341Sdelphij if (!engine_list_remove(e)) { 283296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_REMOVE, ENGINE_R_INTERNAL_LIST_ERROR); 284296341Sdelphij to_return = 0; 285296341Sdelphij } 286296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 287296341Sdelphij return to_return; 288296341Sdelphij} 289109998Smarkm 290109998Smarkmstatic void engine_cpy(ENGINE *dest, const ENGINE *src) 291296341Sdelphij{ 292296341Sdelphij dest->id = src->id; 293296341Sdelphij dest->name = src->name; 294109998Smarkm#ifndef OPENSSL_NO_RSA 295296341Sdelphij dest->rsa_meth = src->rsa_meth; 296109998Smarkm#endif 297109998Smarkm#ifndef OPENSSL_NO_DSA 298296341Sdelphij dest->dsa_meth = src->dsa_meth; 299109998Smarkm#endif 300109998Smarkm#ifndef OPENSSL_NO_DH 301296341Sdelphij dest->dh_meth = src->dh_meth; 302109998Smarkm#endif 303160814Ssimon#ifndef OPENSSL_NO_ECDH 304296341Sdelphij dest->ecdh_meth = src->ecdh_meth; 305160814Ssimon#endif 306160814Ssimon#ifndef OPENSSL_NO_ECDSA 307296341Sdelphij dest->ecdsa_meth = src->ecdsa_meth; 308160814Ssimon#endif 309296341Sdelphij dest->rand_meth = src->rand_meth; 310296341Sdelphij dest->store_meth = src->store_meth; 311296341Sdelphij dest->ciphers = src->ciphers; 312296341Sdelphij dest->digests = src->digests; 313296341Sdelphij dest->pkey_meths = src->pkey_meths; 314296341Sdelphij dest->destroy = src->destroy; 315296341Sdelphij dest->init = src->init; 316296341Sdelphij dest->finish = src->finish; 317296341Sdelphij dest->ctrl = src->ctrl; 318296341Sdelphij dest->load_privkey = src->load_privkey; 319296341Sdelphij dest->load_pubkey = src->load_pubkey; 320296341Sdelphij dest->cmd_defns = src->cmd_defns; 321296341Sdelphij dest->flags = src->flags; 322296341Sdelphij} 323109998Smarkm 324109998SmarkmENGINE *ENGINE_by_id(const char *id) 325296341Sdelphij{ 326296341Sdelphij ENGINE *iterator; 327296341Sdelphij char *load_dir = NULL; 328296341Sdelphij if (id == NULL) { 329296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_BY_ID, ERR_R_PASSED_NULL_PARAMETER); 330296341Sdelphij return NULL; 331296341Sdelphij } 332296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); 333296341Sdelphij iterator = engine_list_head; 334296341Sdelphij while (iterator && (strcmp(id, iterator->id) != 0)) 335296341Sdelphij iterator = iterator->next; 336296341Sdelphij if (iterator) { 337296341Sdelphij /* 338296341Sdelphij * We need to return a structural reference. If this is an ENGINE 339296341Sdelphij * type that returns copies, make a duplicate - otherwise increment 340296341Sdelphij * the existing ENGINE's reference count. 341296341Sdelphij */ 342296341Sdelphij if (iterator->flags & ENGINE_FLAGS_BY_ID_COPY) { 343296341Sdelphij ENGINE *cp = ENGINE_new(); 344296341Sdelphij if (!cp) 345296341Sdelphij iterator = NULL; 346296341Sdelphij else { 347296341Sdelphij engine_cpy(cp, iterator); 348296341Sdelphij iterator = cp; 349296341Sdelphij } 350296341Sdelphij } else { 351296341Sdelphij iterator->struct_ref++; 352296341Sdelphij engine_ref_debug(iterator, 0, 1) 353296341Sdelphij } 354296341Sdelphij } 355296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); 356160814Ssimon#if 0 357296341Sdelphij if (iterator == NULL) { 358296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_BY_ID, ENGINE_R_NO_SUCH_ENGINE); 359296341Sdelphij ERR_add_error_data(2, "id=", id); 360296341Sdelphij } 361296341Sdelphij return iterator; 362160814Ssimon#else 363296341Sdelphij /* EEK! Experimental code starts */ 364296341Sdelphij if (iterator) 365296341Sdelphij return iterator; 366296341Sdelphij /* 367296341Sdelphij * Prevent infinite recusrion if we're looking for the dynamic engine. 368296341Sdelphij */ 369296341Sdelphij if (strcmp(id, "dynamic")) { 370296341Sdelphij# ifdef OPENSSL_SYS_VMS 371296341Sdelphij if ((load_dir = getenv("OPENSSL_ENGINES")) == 0) 372296341Sdelphij load_dir = "SSLROOT:[ENGINES]"; 373296341Sdelphij# else 374296341Sdelphij if ((load_dir = getenv("OPENSSL_ENGINES")) == 0) 375296341Sdelphij load_dir = ENGINESDIR; 376296341Sdelphij# endif 377296341Sdelphij iterator = ENGINE_by_id("dynamic"); 378296341Sdelphij if (!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) || 379296341Sdelphij !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) || 380296341Sdelphij !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD", 381296341Sdelphij load_dir, 0) || 382296341Sdelphij !ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) || 383296341Sdelphij !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0)) 384296341Sdelphij goto notfound; 385296341Sdelphij return iterator; 386296341Sdelphij } 387296341Sdelphij notfound: 388296341Sdelphij ENGINE_free(iterator); 389296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_BY_ID, ENGINE_R_NO_SUCH_ENGINE); 390296341Sdelphij ERR_add_error_data(2, "id=", id); 391296341Sdelphij return NULL; 392296341Sdelphij /* EEK! Experimental code ends */ 393160814Ssimon#endif 394296341Sdelphij} 395109998Smarkm 396109998Smarkmint ENGINE_up_ref(ENGINE *e) 397296341Sdelphij{ 398296341Sdelphij if (e == NULL) { 399296341Sdelphij ENGINEerr(ENGINE_F_ENGINE_UP_REF, ERR_R_PASSED_NULL_PARAMETER); 400296341Sdelphij return 0; 401296341Sdelphij } 402296341Sdelphij CRYPTO_add(&e->struct_ref, 1, CRYPTO_LOCK_ENGINE); 403296341Sdelphij return 1; 404296341Sdelphij} 405