1 /* crypto/engine/eng_list.c */
   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 "eng_int.h"
  65 
  66 /* The linked-list of pointers to engine types. engine_list_head
  67  * incorporates an implicit structural reference but engine_list_tail
  68  * does not - the latter is a computational niceity and only points
  69  * to something that is already pointed to by its predecessor in the
  70  * list (or engine_list_head itself). In the same way, the use of the
  71  * "prev" pointer in each ENGINE is to save excessive list iteration,
  72  * it doesn't correspond to an extra structural reference. Hence,
  73  * engine_list_head, and each non-null "next" pointer account for
  74  * the list itself assuming exactly 1 structural reference on each
  75  * list member. */
  76 static ENGINE *engine_list_head = NULL;
  77 static ENGINE *engine_list_tail = NULL;
  78 
  79 /* This cleanup function is only needed internally. If it should be called, we
  80  * register it with the "ENGINE_cleanup()" stack to be called during cleanup. */
  81 
  82 static void engine_list_cleanup(void)
  83         {
  84         ENGINE *iterator = engine_list_head;
  85 
  86         while(iterator != NULL)
  87                 {
  88                 ENGINE_remove(iterator);
  89                 iterator = engine_list_head;
  90                 }
  91         return;
  92         }
  93 
  94 /* These static functions starting with a lower case "engine_" always
  95  * take place when CRYPTO_LOCK_ENGINE has been locked up. */
  96 static int engine_list_add(ENGINE *e)
  97         {
  98         int conflict = 0;
  99         ENGINE *iterator = NULL;
 100 
 101         if(e == NULL)
 102                 {
 103                 ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
 104                         ERR_R_PASSED_NULL_PARAMETER);
 105                 return 0;
 106                 }
 107         iterator = engine_list_head;
 108         while(iterator && !conflict)
 109                 {
 110                 conflict = (strcmp(iterator->id, e->id) == 0);
 111                 iterator = iterator->next;
 112                 }
 113         if(conflict)
 114                 {
 115                 ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
 116                         ENGINE_R_CONFLICTING_ENGINE_ID);
 117                 return 0;
 118                 }
 119         if(engine_list_head == NULL)
 120                 {
 121                 /* We are adding to an empty list. */
 122                 if(engine_list_tail)
 123                         {
 124                         ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
 125                                 ENGINE_R_INTERNAL_LIST_ERROR);
 126                         return 0;
 127                         }
 128                 engine_list_head = e;
 129                 e->prev = NULL;
 130                 /* The first time the list allocates, we should register the
 131                  * cleanup. */
 132                 engine_cleanup_add_last(engine_list_cleanup);
 133                 }
 134         else
 135                 {
 136                 /* We are adding to the tail of an existing list. */
 137                 if((engine_list_tail == NULL) ||
 138                                 (engine_list_tail->next != NULL))
 139                         {
 140                         ENGINEerr(ENGINE_F_ENGINE_LIST_ADD,
 141                                 ENGINE_R_INTERNAL_LIST_ERROR);
 142                         return 0;
 143                         }
 144                 engine_list_tail->next = e;
 145                 e->prev = engine_list_tail;
 146                 }
 147         /* Having the engine in the list assumes a structural
 148          * reference. */
 149         e->struct_ref++;
 150         engine_ref_debug(e, 0, 1)
 151         /* However it came to be, e is the last item in the list. */
 152         engine_list_tail = e;
 153         e->next = NULL;
 154         return 1;
 155         }
 156 
 157 static int engine_list_remove(ENGINE *e)
 158         {
 159         ENGINE *iterator;
 160 
 161         if(e == NULL)
 162                 {
 163                 ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE,
 164                         ERR_R_PASSED_NULL_PARAMETER);
 165                 return 0;
 166                 }
 167         /* We need to check that e is in our linked list! */
 168         iterator = engine_list_head;
 169         while(iterator && (iterator != e))
 170                 iterator = iterator->next;
 171         if(iterator == NULL)
 172                 {
 173                 ENGINEerr(ENGINE_F_ENGINE_LIST_REMOVE,
 174                         ENGINE_R_ENGINE_IS_NOT_IN_LIST);
 175                 return 0;
 176                 }
 177         /* un-link e from the chain. */
 178         if(e->next)
 179                 e->next->prev = e->prev;
 180         if(e->prev)
 181                 e->prev->next = e->next;
 182         /* Correct our head/tail if necessary. */
 183         if(engine_list_head == e)
 184                 engine_list_head = e->next;
 185         if(engine_list_tail == e)
 186                 engine_list_tail = e->prev;
 187         engine_free_util(e, 0);
 188         return 1;
 189         }
 190 
 191 /* Get the first/last "ENGINE" type available. */
 192 ENGINE *ENGINE_get_first(void)
 193         {
 194         ENGINE *ret;
 195 
 196         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
 197         ret = engine_list_head;
 198         if(ret)
 199                 {
 200                 ret->struct_ref++;
 201                 engine_ref_debug(ret, 0, 1)
 202                 }
 203         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
 204         return ret;
 205         }
 206 
 207 ENGINE *ENGINE_get_last(void)
 208         {
 209         ENGINE *ret;
 210 
 211         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
 212         ret = engine_list_tail;
 213         if(ret)
 214                 {
 215                 ret->struct_ref++;
 216                 engine_ref_debug(ret, 0, 1)
 217                 }
 218         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
 219         return ret;
 220         }
 221 
 222 /* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
 223 ENGINE *ENGINE_get_next(ENGINE *e)
 224         {
 225         ENGINE *ret = NULL;
 226         if(e == NULL)
 227                 {
 228                 ENGINEerr(ENGINE_F_ENGINE_GET_NEXT,
 229                         ERR_R_PASSED_NULL_PARAMETER);
 230                 return 0;
 231                 }
 232         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
 233         ret = e->next;
 234         if(ret)
 235                 {
 236                 /* Return a valid structural refernce to the next ENGINE */
 237                 ret->struct_ref++;
 238                 engine_ref_debug(ret, 0, 1)
 239                 }
 240         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
 241         /* Release the structural reference to the previous ENGINE */
 242         ENGINE_free(e);
 243         return ret;
 244         }
 245 
 246 ENGINE *ENGINE_get_prev(ENGINE *e)
 247         {
 248         ENGINE *ret = NULL;
 249         if(e == NULL)
 250                 {
 251                 ENGINEerr(ENGINE_F_ENGINE_GET_PREV,
 252                         ERR_R_PASSED_NULL_PARAMETER);
 253                 return 0;
 254                 }
 255         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
 256         ret = e->prev;
 257         if(ret)
 258                 {
 259                 /* Return a valid structural reference to the next ENGINE */
 260                 ret->struct_ref++;
 261                 engine_ref_debug(ret, 0, 1)
 262                 }
 263         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
 264         /* Release the structural reference to the previous ENGINE */
 265         ENGINE_free(e);
 266         return ret;
 267         }
 268 
 269 /* Add another "ENGINE" type into the list. */
 270 int ENGINE_add(ENGINE *e)
 271         {
 272         int to_return = 1;
 273         if(e == NULL)
 274                 {
 275                 ENGINEerr(ENGINE_F_ENGINE_ADD,
 276                         ERR_R_PASSED_NULL_PARAMETER);
 277                 return 0;
 278                 }
 279         if((e->id == NULL) || (e->name == NULL))
 280                 {
 281                 ENGINEerr(ENGINE_F_ENGINE_ADD,
 282                         ENGINE_R_ID_OR_NAME_MISSING);
 283                 }
 284         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
 285         if(!engine_list_add(e))
 286                 {
 287                 ENGINEerr(ENGINE_F_ENGINE_ADD,
 288                         ENGINE_R_INTERNAL_LIST_ERROR);
 289                 to_return = 0;
 290                 }
 291         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
 292         return to_return;
 293         }
 294 
 295 /* Remove an existing "ENGINE" type from the array. */
 296 int ENGINE_remove(ENGINE *e)
 297         {
 298         int to_return = 1;
 299         if(e == NULL)
 300                 {
 301                 ENGINEerr(ENGINE_F_ENGINE_REMOVE,
 302                         ERR_R_PASSED_NULL_PARAMETER);
 303                 return 0;
 304                 }
 305         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
 306         if(!engine_list_remove(e))
 307                 {
 308                 ENGINEerr(ENGINE_F_ENGINE_REMOVE,
 309                         ENGINE_R_INTERNAL_LIST_ERROR);
 310                 to_return = 0;
 311                 }
 312         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
 313         return to_return;
 314         }
 315 
 316 static void engine_cpy(ENGINE *dest, const ENGINE *src)
 317         {
 318         dest->id = src->id;
 319         dest->name = src->name;
 320 #ifndef OPENSSL_NO_RSA
 321         dest->rsa_meth = src->rsa_meth;
 322 #endif
 323 #ifndef OPENSSL_NO_DSA
 324         dest->dsa_meth = src->dsa_meth;
 325 #endif
 326 #ifndef OPENSSL_NO_DH
 327         dest->dh_meth = src->dh_meth;
 328 #endif
 329 #ifndef OPENSSL_NO_ECDH
 330         dest->ecdh_meth = src->ecdh_meth;
 331 #endif
 332 #ifndef OPENSSL_NO_ECDSA
 333         dest->ecdsa_meth = src->ecdsa_meth;
 334 #endif
 335         dest->rand_meth = src->rand_meth;
 336         dest->store_meth = src->store_meth;
 337         dest->ciphers = src->ciphers;
 338         dest->digests = src->digests;
 339         dest->pkey_meths = src->pkey_meths;
 340         dest->destroy = src->destroy;
 341         dest->init = src->init;
 342         dest->finish = src->finish;
 343         dest->ctrl = src->ctrl;
 344         dest->load_privkey = src->load_privkey;
 345         dest->load_pubkey = src->load_pubkey;
 346         dest->cmd_defns = src->cmd_defns;
 347         dest->flags = src->flags;
 348         }
 349 
 350 ENGINE *ENGINE_by_id(const char *id)
 351         {
 352         ENGINE *iterator;
 353         char *load_dir = NULL;
 354         if(id == NULL)
 355                 {
 356                 ENGINEerr(ENGINE_F_ENGINE_BY_ID,
 357                         ERR_R_PASSED_NULL_PARAMETER);
 358                 return NULL;
 359                 }
 360         CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
 361         iterator = engine_list_head;
 362         while(iterator && (strcmp(id, iterator->id) != 0))
 363                 iterator = iterator->next;
 364         if(iterator)
 365                 {
 366                 /* We need to return a structural reference. If this is an
 367                  * ENGINE type that returns copies, make a duplicate - otherwise
 368                  * increment the existing ENGINE's reference count. */
 369                 if(iterator->flags & ENGINE_FLAGS_BY_ID_COPY)
 370                         {
 371                         ENGINE *cp = ENGINE_new();
 372                         if(!cp)
 373                                 iterator = NULL;
 374                         else
 375                                 {
 376                                 engine_cpy(cp, iterator);
 377                                 iterator = cp;
 378                                 }
 379                         }
 380                 else
 381                         {
 382                         iterator->struct_ref++;
 383                         engine_ref_debug(iterator, 0, 1)
 384                         }
 385                 }
 386         CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
 387 #if 0
 388         if(iterator == NULL)
 389                 {
 390                 ENGINEerr(ENGINE_F_ENGINE_BY_ID,
 391                         ENGINE_R_NO_SUCH_ENGINE);
 392                 ERR_add_error_data(2, "id=", id);
 393                 }
 394         return iterator;
 395 #else
 396         /* EEK! Experimental code starts */
 397         if(iterator) return iterator;
 398         /* Prevent infinite recusrion if we're looking for the dynamic engine. */
 399         if (strcmp(id, "dynamic"))
 400                 {
 401 #ifdef OPENSSL_SYS_VMS
 402                 if((load_dir = getenv("OPENSSL_ENGINES")) == 0) load_dir = "SSLROOT:[ENGINES]";
 403 #else
 404                 if((load_dir = getenv("OPENSSL_ENGINES")) == 0) load_dir = ENGINESDIR;
 405 #endif
 406                 iterator = ENGINE_by_id("dynamic");
 407                 if(!iterator || !ENGINE_ctrl_cmd_string(iterator, "ID", id, 0) ||
 408                                 !ENGINE_ctrl_cmd_string(iterator, "DIR_LOAD", "2", 0) ||
 409                                 !ENGINE_ctrl_cmd_string(iterator, "DIR_ADD",
 410                                         load_dir, 0) ||
 411                                 !ENGINE_ctrl_cmd_string(iterator, "LIST_ADD", "1", 0) ||
 412                                 !ENGINE_ctrl_cmd_string(iterator, "LOAD", NULL, 0))
 413                                 goto notfound;
 414                 return iterator;
 415                 }
 416 notfound:
 417         ENGINE_free(iterator);
 418         ENGINEerr(ENGINE_F_ENGINE_BY_ID,ENGINE_R_NO_SUCH_ENGINE);
 419         ERR_add_error_data(2, "id=", id);
 420         return NULL;
 421         /* EEK! Experimental code ends */
 422 #endif
 423         }
 424 
 425 int ENGINE_up_ref(ENGINE *e)
 426         {
 427         if (e == NULL)
 428                 {
 429                 ENGINEerr(ENGINE_F_ENGINE_UP_REF,ERR_R_PASSED_NULL_PARAMETER);
 430                 return 0;
 431                 }
 432         CRYPTO_add(&e->struct_ref,1,CRYPTO_LOCK_ENGINE);
 433         return 1;
 434         }