10Sstevel@tonic-gate /* ====================================================================
20Sstevel@tonic-gate * Copyright (c) 2001 The OpenSSL Project. All rights reserved.
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
50Sstevel@tonic-gate * modification, are permitted provided that the following conditions
60Sstevel@tonic-gate * are met:
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
90Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
100Sstevel@tonic-gate *
110Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
120Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in
130Sstevel@tonic-gate * the documentation and/or other materials provided with the
140Sstevel@tonic-gate * distribution.
150Sstevel@tonic-gate *
160Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this
170Sstevel@tonic-gate * software must display the following acknowledgment:
180Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project
190Sstevel@tonic-gate * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
200Sstevel@tonic-gate *
210Sstevel@tonic-gate * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
220Sstevel@tonic-gate * endorse or promote products derived from this software without
230Sstevel@tonic-gate * prior written permission. For written permission, please contact
240Sstevel@tonic-gate * licensing@OpenSSL.org.
250Sstevel@tonic-gate *
260Sstevel@tonic-gate * 5. Products derived from this software may not be called "OpenSSL"
270Sstevel@tonic-gate * nor may "OpenSSL" appear in their names without prior written
280Sstevel@tonic-gate * permission of the OpenSSL Project.
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * 6. Redistributions of any form whatsoever must retain the following
310Sstevel@tonic-gate * acknowledgment:
320Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project
330Sstevel@tonic-gate * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
340Sstevel@tonic-gate *
350Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
360Sstevel@tonic-gate * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
370Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
380Sstevel@tonic-gate * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
390Sstevel@tonic-gate * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
400Sstevel@tonic-gate * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
410Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
420Sstevel@tonic-gate * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
430Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
440Sstevel@tonic-gate * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
450Sstevel@tonic-gate * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
460Sstevel@tonic-gate * OF THE POSSIBILITY OF SUCH DAMAGE.
470Sstevel@tonic-gate * ====================================================================
480Sstevel@tonic-gate *
490Sstevel@tonic-gate * This product includes cryptographic software written by Eric Young
500Sstevel@tonic-gate * (eay@cryptsoft.com). This product includes software written by Tim
510Sstevel@tonic-gate * Hudson (tjh@cryptsoft.com).
520Sstevel@tonic-gate *
530Sstevel@tonic-gate */
540Sstevel@tonic-gate
55*2139Sjp161948 #include "cryptlib.h"
560Sstevel@tonic-gate #include <openssl/evp.h>
57*2139Sjp161948 #include <openssl/lhash.h>
580Sstevel@tonic-gate #include "eng_int.h"
590Sstevel@tonic-gate
600Sstevel@tonic-gate /* The type of the items in the table */
610Sstevel@tonic-gate typedef struct st_engine_pile
620Sstevel@tonic-gate {
63*2139Sjp161948 /* The 'nid' of this algorithm/mode */
640Sstevel@tonic-gate int nid;
65*2139Sjp161948 /* ENGINEs that implement this algorithm/mode. */
660Sstevel@tonic-gate STACK_OF(ENGINE) *sk;
670Sstevel@tonic-gate /* The default ENGINE to perform this algorithm/mode. */
680Sstevel@tonic-gate ENGINE *funct;
69*2139Sjp161948 /* Zero if 'sk' is newer than the cached 'funct', non-zero otherwise */
700Sstevel@tonic-gate int uptodate;
710Sstevel@tonic-gate } ENGINE_PILE;
720Sstevel@tonic-gate
73*2139Sjp161948 /* The type exposed in eng_int.h */
740Sstevel@tonic-gate struct st_engine_table
750Sstevel@tonic-gate {
760Sstevel@tonic-gate LHASH piles;
770Sstevel@tonic-gate }; /* ENGINE_TABLE */
780Sstevel@tonic-gate
79*2139Sjp161948 /* Global flags (ENGINE_TABLE_FLAG_***). */
800Sstevel@tonic-gate static unsigned int table_flags = 0;
810Sstevel@tonic-gate
820Sstevel@tonic-gate /* API function manipulating 'table_flags' */
ENGINE_get_table_flags(void)830Sstevel@tonic-gate unsigned int ENGINE_get_table_flags(void)
840Sstevel@tonic-gate {
850Sstevel@tonic-gate return table_flags;
860Sstevel@tonic-gate }
ENGINE_set_table_flags(unsigned int flags)870Sstevel@tonic-gate void ENGINE_set_table_flags(unsigned int flags)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate table_flags = flags;
900Sstevel@tonic-gate }
910Sstevel@tonic-gate
920Sstevel@tonic-gate /* Internal functions for the "piles" hash table */
engine_pile_hash(const ENGINE_PILE * c)930Sstevel@tonic-gate static unsigned long engine_pile_hash(const ENGINE_PILE *c)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate return c->nid;
960Sstevel@tonic-gate }
engine_pile_cmp(const ENGINE_PILE * a,const ENGINE_PILE * b)970Sstevel@tonic-gate static int engine_pile_cmp(const ENGINE_PILE *a, const ENGINE_PILE *b)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate return a->nid - b->nid;
1000Sstevel@tonic-gate }
IMPLEMENT_LHASH_HASH_FN(engine_pile_hash,const ENGINE_PILE *)1010Sstevel@tonic-gate static IMPLEMENT_LHASH_HASH_FN(engine_pile_hash, const ENGINE_PILE *)
1020Sstevel@tonic-gate static IMPLEMENT_LHASH_COMP_FN(engine_pile_cmp, const ENGINE_PILE *)
1030Sstevel@tonic-gate static int int_table_check(ENGINE_TABLE **t, int create)
1040Sstevel@tonic-gate {
1050Sstevel@tonic-gate LHASH *lh;
106*2139Sjp161948 if(*t) return 1;
107*2139Sjp161948 if(!create) return 0;
1080Sstevel@tonic-gate if((lh = lh_new(LHASH_HASH_FN(engine_pile_hash),
1090Sstevel@tonic-gate LHASH_COMP_FN(engine_pile_cmp))) == NULL)
1100Sstevel@tonic-gate return 0;
1110Sstevel@tonic-gate *t = (ENGINE_TABLE *)lh;
1120Sstevel@tonic-gate return 1;
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate /* Privately exposed (via eng_int.h) functions for adding and/or removing
1160Sstevel@tonic-gate * ENGINEs from the implementation table */
engine_table_register(ENGINE_TABLE ** table,ENGINE_CLEANUP_CB * cleanup,ENGINE * e,const int * nids,int num_nids,int setdefault)1170Sstevel@tonic-gate int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
1180Sstevel@tonic-gate ENGINE *e, const int *nids, int num_nids, int setdefault)
1190Sstevel@tonic-gate {
1200Sstevel@tonic-gate int ret = 0, added = 0;
1210Sstevel@tonic-gate ENGINE_PILE tmplate, *fnd;
1220Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
1230Sstevel@tonic-gate if(!(*table))
1240Sstevel@tonic-gate added = 1;
1250Sstevel@tonic-gate if(!int_table_check(table, 1))
1260Sstevel@tonic-gate goto end;
1270Sstevel@tonic-gate if(added)
1280Sstevel@tonic-gate /* The cleanup callback needs to be added */
1290Sstevel@tonic-gate engine_cleanup_add_first(cleanup);
1300Sstevel@tonic-gate while(num_nids--)
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate tmplate.nid = *nids;
1330Sstevel@tonic-gate fnd = lh_retrieve(&(*table)->piles, &tmplate);
1340Sstevel@tonic-gate if(!fnd)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate fnd = OPENSSL_malloc(sizeof(ENGINE_PILE));
137*2139Sjp161948 if(!fnd) goto end;
138*2139Sjp161948 fnd->uptodate = 0;
1390Sstevel@tonic-gate fnd->nid = *nids;
1400Sstevel@tonic-gate fnd->sk = sk_ENGINE_new_null();
1410Sstevel@tonic-gate if(!fnd->sk)
1420Sstevel@tonic-gate {
1430Sstevel@tonic-gate OPENSSL_free(fnd);
1440Sstevel@tonic-gate goto end;
1450Sstevel@tonic-gate }
146*2139Sjp161948 fnd->funct = NULL;
1470Sstevel@tonic-gate lh_insert(&(*table)->piles, fnd);
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate /* A registration shouldn't add duplciate entries */
1500Sstevel@tonic-gate sk_ENGINE_delete_ptr(fnd->sk, e);
1510Sstevel@tonic-gate /* if 'setdefault', this ENGINE goes to the head of the list */
1520Sstevel@tonic-gate if(!sk_ENGINE_push(fnd->sk, e))
1530Sstevel@tonic-gate goto end;
1540Sstevel@tonic-gate /* "touch" this ENGINE_PILE */
155*2139Sjp161948 fnd->uptodate = 1;
1560Sstevel@tonic-gate if(setdefault)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate if(!engine_unlocked_init(e))
1590Sstevel@tonic-gate {
1600Sstevel@tonic-gate ENGINEerr(ENGINE_F_ENGINE_TABLE_REGISTER,
1610Sstevel@tonic-gate ENGINE_R_INIT_FAILED);
1620Sstevel@tonic-gate goto end;
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate if(fnd->funct)
1650Sstevel@tonic-gate engine_unlocked_finish(fnd->funct, 0);
1660Sstevel@tonic-gate fnd->funct = e;
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate nids++;
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate ret = 1;
1710Sstevel@tonic-gate end:
1720Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
1730Sstevel@tonic-gate return ret;
1740Sstevel@tonic-gate }
int_unregister_cb(ENGINE_PILE * pile,ENGINE * e)1750Sstevel@tonic-gate static void int_unregister_cb(ENGINE_PILE *pile, ENGINE *e)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate int n;
1780Sstevel@tonic-gate /* Iterate the 'c->sk' stack removing any occurance of 'e' */
1790Sstevel@tonic-gate while((n = sk_ENGINE_find(pile->sk, e)) >= 0)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate sk_ENGINE_delete(pile->sk, n);
1820Sstevel@tonic-gate /* "touch" this ENGINE_CIPHER */
183*2139Sjp161948 pile->uptodate = 1;
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate if(pile->funct == e)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate engine_unlocked_finish(e, 0);
1880Sstevel@tonic-gate pile->funct = NULL;
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate }
IMPLEMENT_LHASH_DOALL_ARG_FN(int_unregister_cb,ENGINE_PILE *,ENGINE *)1910Sstevel@tonic-gate static IMPLEMENT_LHASH_DOALL_ARG_FN(int_unregister_cb,ENGINE_PILE *,ENGINE *)
1920Sstevel@tonic-gate void engine_table_unregister(ENGINE_TABLE **table, ENGINE *e)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
1950Sstevel@tonic-gate if(int_table_check(table, 0))
1960Sstevel@tonic-gate lh_doall_arg(&(*table)->piles,
1970Sstevel@tonic-gate LHASH_DOALL_ARG_FN(int_unregister_cb), e);
1980Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate
int_cleanup_cb(ENGINE_PILE * p)2010Sstevel@tonic-gate static void int_cleanup_cb(ENGINE_PILE *p)
2020Sstevel@tonic-gate {
2030Sstevel@tonic-gate sk_ENGINE_free(p->sk);
2040Sstevel@tonic-gate if(p->funct)
2050Sstevel@tonic-gate engine_unlocked_finish(p->funct, 0);
2060Sstevel@tonic-gate OPENSSL_free(p);
2070Sstevel@tonic-gate }
IMPLEMENT_LHASH_DOALL_FN(int_cleanup_cb,ENGINE_PILE *)2080Sstevel@tonic-gate static IMPLEMENT_LHASH_DOALL_FN(int_cleanup_cb,ENGINE_PILE *)
2090Sstevel@tonic-gate void engine_table_cleanup(ENGINE_TABLE **table)
2100Sstevel@tonic-gate {
2110Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
2120Sstevel@tonic-gate if(*table)
2130Sstevel@tonic-gate {
2140Sstevel@tonic-gate lh_doall(&(*table)->piles, LHASH_DOALL_FN(int_cleanup_cb));
2150Sstevel@tonic-gate lh_free(&(*table)->piles);
2160Sstevel@tonic-gate *table = NULL;
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate
221*2139Sjp161948 /* return a functional reference for a given 'nid' */
2220Sstevel@tonic-gate #ifndef ENGINE_TABLE_DEBUG
engine_table_select(ENGINE_TABLE ** table,int nid)2230Sstevel@tonic-gate ENGINE *engine_table_select(ENGINE_TABLE **table, int nid)
2240Sstevel@tonic-gate #else
2250Sstevel@tonic-gate ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f, int l)
2260Sstevel@tonic-gate #endif
2270Sstevel@tonic-gate {
2280Sstevel@tonic-gate ENGINE *ret = NULL;
2290Sstevel@tonic-gate ENGINE_PILE tmplate, *fnd=NULL;
2300Sstevel@tonic-gate int initres, loop = 0;
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate if(!(*table))
2330Sstevel@tonic-gate {
2340Sstevel@tonic-gate #ifdef ENGINE_TABLE_DEBUG
235*2139Sjp161948 fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing "
236*2139Sjp161948 "registered!\n", f, l, nid);
2370Sstevel@tonic-gate #endif
2380Sstevel@tonic-gate return NULL;
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
2410Sstevel@tonic-gate /* Check again inside the lock otherwise we could race against cleanup
2420Sstevel@tonic-gate * operations. But don't worry about a fprintf(stderr). */
243*2139Sjp161948 if(!int_table_check(table, 0)) goto end;
2440Sstevel@tonic-gate tmplate.nid = nid;
2450Sstevel@tonic-gate fnd = lh_retrieve(&(*table)->piles, &tmplate);
246*2139Sjp161948 if(!fnd) goto end;
2470Sstevel@tonic-gate if(fnd->funct && engine_unlocked_init(fnd->funct))
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate #ifdef ENGINE_TABLE_DEBUG
2500Sstevel@tonic-gate fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
2510Sstevel@tonic-gate "ENGINE '%s' cached\n", f, l, nid, fnd->funct->id);
2520Sstevel@tonic-gate #endif
2530Sstevel@tonic-gate ret = fnd->funct;
2540Sstevel@tonic-gate goto end;
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate if(fnd->uptodate)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate ret = fnd->funct;
2590Sstevel@tonic-gate goto end;
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate trynext:
2620Sstevel@tonic-gate ret = sk_ENGINE_value(fnd->sk, loop++);
2630Sstevel@tonic-gate if(!ret)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate #ifdef ENGINE_TABLE_DEBUG
2660Sstevel@tonic-gate fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no "
2670Sstevel@tonic-gate "registered implementations would initialise\n",
2680Sstevel@tonic-gate f, l, nid);
2690Sstevel@tonic-gate #endif
2700Sstevel@tonic-gate goto end;
2710Sstevel@tonic-gate }
272*2139Sjp161948 /* Try to initialise the ENGINE? */
2730Sstevel@tonic-gate if((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT))
2740Sstevel@tonic-gate initres = engine_unlocked_init(ret);
2750Sstevel@tonic-gate else
2760Sstevel@tonic-gate initres = 0;
2770Sstevel@tonic-gate if(initres)
2780Sstevel@tonic-gate {
279*2139Sjp161948 /* Update 'funct' */
2800Sstevel@tonic-gate if((fnd->funct != ret) && engine_unlocked_init(ret))
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate /* If there was a previous default we release it. */
2830Sstevel@tonic-gate if(fnd->funct)
2840Sstevel@tonic-gate engine_unlocked_finish(fnd->funct, 0);
2850Sstevel@tonic-gate fnd->funct = ret;
2860Sstevel@tonic-gate #ifdef ENGINE_TABLE_DEBUG
2870Sstevel@tonic-gate fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, "
2880Sstevel@tonic-gate "setting default to '%s'\n", f, l, nid, ret->id);
2890Sstevel@tonic-gate #endif
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate #ifdef ENGINE_TABLE_DEBUG
2920Sstevel@tonic-gate fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
2930Sstevel@tonic-gate "newly initialised '%s'\n", f, l, nid, ret->id);
2940Sstevel@tonic-gate #endif
2950Sstevel@tonic-gate goto end;
2960Sstevel@tonic-gate }
2970Sstevel@tonic-gate goto trynext;
2980Sstevel@tonic-gate end:
299*2139Sjp161948 /* If it failed, it is unlikely to succeed again until some future
300*2139Sjp161948 * registrations have taken place. In all cases, we cache. */
301*2139Sjp161948 if(fnd) fnd->uptodate = 1;
3020Sstevel@tonic-gate #ifdef ENGINE_TABLE_DEBUG
3030Sstevel@tonic-gate if(ret)
3040Sstevel@tonic-gate fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
3050Sstevel@tonic-gate "ENGINE '%s'\n", f, l, nid, ret->id);
3060Sstevel@tonic-gate else
3070Sstevel@tonic-gate fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
3080Sstevel@tonic-gate "'no matching ENGINE'\n", f, l, nid);
3090Sstevel@tonic-gate #endif
3100Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
3110Sstevel@tonic-gate /* Whatever happened, any failed init()s are not failures in this
3120Sstevel@tonic-gate * context, so clear our error state. */
3130Sstevel@tonic-gate ERR_clear_error();
3140Sstevel@tonic-gate return ret;
3150Sstevel@tonic-gate }
316