GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/engine/eng_table.c Lines: 9 109 8.3 %
Date: 2017-11-07 Branches: 1 66 1.5 %

Line Branch Exec Source
1
/* $OpenBSD: eng_table.c,v 1.9 2017/01/29 17:49:23 beck Exp $ */
2
/* ====================================================================
3
 * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 *
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in
14
 *    the documentation and/or other materials provided with the
15
 *    distribution.
16
 *
17
 * 3. All advertising materials mentioning features or use of this
18
 *    software must display the following acknowledgment:
19
 *    "This product includes software developed by the OpenSSL Project
20
 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
21
 *
22
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23
 *    endorse or promote products derived from this software without
24
 *    prior written permission. For written permission, please contact
25
 *    licensing@OpenSSL.org.
26
 *
27
 * 5. Products derived from this software may not be called "OpenSSL"
28
 *    nor may "OpenSSL" appear in their names without prior written
29
 *    permission of the OpenSSL Project.
30
 *
31
 * 6. Redistributions of any form whatsoever must retain the following
32
 *    acknowledgment:
33
 *    "This product includes software developed by the OpenSSL Project
34
 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
35
 *
36
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47
 * OF THE POSSIBILITY OF SUCH DAMAGE.
48
 * ====================================================================
49
 *
50
 * This product includes cryptographic software written by Eric Young
51
 * (eay@cryptsoft.com).  This product includes software written by Tim
52
 * Hudson (tjh@cryptsoft.com).
53
 *
54
 */
55
56
#include <openssl/err.h>
57
#include <openssl/evp.h>
58
#include <openssl/lhash.h>
59
60
#include "eng_int.h"
61
62
/* The type of the items in the table */
63
typedef struct st_engine_pile {
64
	/* The 'nid' of this algorithm/mode */
65
	int nid;
66
	/* ENGINEs that implement this algorithm/mode. */
67
	STACK_OF(ENGINE) *sk;
68
	/* The default ENGINE to perform this algorithm/mode. */
69
	ENGINE *funct;
70
	/* Zero if 'sk' is newer than the cached 'funct', non-zero otherwise */
71
	int uptodate;
72
} ENGINE_PILE;
73
74
DECLARE_LHASH_OF(ENGINE_PILE);
75
76
/* The type exposed in eng_int.h */
77
struct st_engine_table {
78
	LHASH_OF(ENGINE_PILE) piles;
79
}; /* ENGINE_TABLE */
80
81
typedef struct st_engine_pile_doall {
82
	engine_table_doall_cb *cb;
83
	void *arg;
84
} ENGINE_PILE_DOALL;
85
86
/* Global flags (ENGINE_TABLE_FLAG_***). */
87
static unsigned int table_flags = 0;
88
89
/* API function manipulating 'table_flags' */
90
unsigned int
91
ENGINE_get_table_flags(void)
92
{
93
	return table_flags;
94
}
95
96
void
97
ENGINE_set_table_flags(unsigned int flags)
98
{
99
	table_flags = flags;
100
}
101
102
/* Internal functions for the "piles" hash table */
103
static unsigned long
104
engine_pile_hash(const ENGINE_PILE *c)
105
{
106
	return c->nid;
107
}
108
109
static int
110
engine_pile_cmp(const ENGINE_PILE *a, const ENGINE_PILE *b)
111
{
112
	return a->nid - b->nid;
113
}
114
static IMPLEMENT_LHASH_HASH_FN(engine_pile, ENGINE_PILE)
115
static IMPLEMENT_LHASH_COMP_FN(engine_pile, ENGINE_PILE)
116
117
static int
118
int_table_check(ENGINE_TABLE **t, int create)
119
{
120
	LHASH_OF(ENGINE_PILE) *lh;
121
122
	if (*t)
123
		return 1;
124
	if (!create)
125
		return 0;
126
	if ((lh = lh_ENGINE_PILE_new()) == NULL)
127
		return 0;
128
	*t = (ENGINE_TABLE *)lh;
129
	return 1;
130
}
131
132
/* Privately exposed (via eng_int.h) functions for adding and/or removing
133
 * ENGINEs from the implementation table */
134
int
135
engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
136
    ENGINE *e, const int *nids, int num_nids, int setdefault)
137
{
138
	int ret = 0, added = 0;
139
	ENGINE_PILE tmplate, *fnd;
140
141
	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
142
	if (!(*table))
143
		added = 1;
144
	if (!int_table_check(table, 1))
145
		goto end;
146
	if (added)
147
		/* The cleanup callback needs to be added */
148
		engine_cleanup_add_first(cleanup);
149
	while (num_nids--) {
150
		tmplate.nid = *nids;
151
		fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate);
152
		if (!fnd) {
153
			fnd = malloc(sizeof(ENGINE_PILE));
154
			if (!fnd)
155
				goto end;
156
			fnd->uptodate = 1;
157
			fnd->nid = *nids;
158
			fnd->sk = sk_ENGINE_new_null();
159
			if (!fnd->sk) {
160
				free(fnd);
161
				goto end;
162
			}
163
			fnd->funct = NULL;
164
			(void)lh_ENGINE_PILE_insert(&(*table)->piles, fnd);
165
		}
166
		/* A registration shouldn't add duplciate entries */
167
		(void)sk_ENGINE_delete_ptr(fnd->sk, e);
168
		/* if 'setdefault', this ENGINE goes to the head of the list */
169
		if (!sk_ENGINE_push(fnd->sk, e))
170
			goto end;
171
		/* "touch" this ENGINE_PILE */
172
		fnd->uptodate = 0;
173
		if (setdefault) {
174
			if (!engine_unlocked_init(e)) {
175
				ENGINEerror(ENGINE_R_INIT_FAILED);
176
				goto end;
177
			}
178
			if (fnd->funct)
179
				engine_unlocked_finish(fnd->funct, 0);
180
			fnd->funct = e;
181
			fnd->uptodate = 1;
182
		}
183
		nids++;
184
	}
185
	ret = 1;
186
end:
187
	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
188
	return ret;
189
}
190
191
static void
192
int_unregister_cb_doall_arg(ENGINE_PILE *pile, ENGINE *e)
193
{
194
	int n;
195
196
	/* Iterate the 'c->sk' stack removing any occurance of 'e' */
197
	while ((n = sk_ENGINE_find(pile->sk, e)) >= 0) {
198
		(void)sk_ENGINE_delete(pile->sk, n);
199
		pile->uptodate = 0;
200
	}
201
	if (pile->funct == e) {
202
		engine_unlocked_finish(e, 0);
203
		pile->funct = NULL;
204
	}
205
}
206
static IMPLEMENT_LHASH_DOALL_ARG_FN(int_unregister_cb, ENGINE_PILE, ENGINE)
207
208
void
209
engine_table_unregister(ENGINE_TABLE **table, ENGINE *e)
210
{
211
	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
212
	if (int_table_check(table, 0))
213
		lh_ENGINE_PILE_doall_arg(&(*table)->piles,
214
		    LHASH_DOALL_ARG_FN(int_unregister_cb), ENGINE, e);
215
	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
216
}
217
218
static void
219
int_cleanup_cb_doall(ENGINE_PILE *p)
220
{
221
	sk_ENGINE_free(p->sk);
222
	if (p->funct)
223
		engine_unlocked_finish(p->funct, 0);
224
	free(p);
225
}
226
static IMPLEMENT_LHASH_DOALL_FN(int_cleanup_cb, ENGINE_PILE)
227
228
void
229
engine_table_cleanup(ENGINE_TABLE **table)
230
{
231
	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
232
	if (*table) {
233
		lh_ENGINE_PILE_doall(&(*table)->piles,
234
		    LHASH_DOALL_FN(int_cleanup_cb));
235
		lh_ENGINE_PILE_free(&(*table)->piles);
236
		*table = NULL;
237
	}
238
	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
239
}
240
241
/* return a functional reference for a given 'nid' */
242
#ifndef ENGINE_TABLE_DEBUG
243
ENGINE *
244
engine_table_select(ENGINE_TABLE **table, int nid)
245
#else
246
ENGINE *
247
engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f, int l)
248
#endif
249
{
250
	ENGINE *ret = NULL;
251
1062008
	ENGINE_PILE tmplate, *fnd = NULL;
252
	int initres, loop = 0;
253
254
531004
	if (!(*table)) {
255
#ifdef ENGINE_TABLE_DEBUG
256
		fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing "
257
		    "registered!\n", f, l, nid);
258
#endif
259
531004
		return NULL;
260
	}
261
	ERR_set_mark();
262
	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
263
	/* Check again inside the lock otherwise we could race against cleanup
264
	 * operations. But don't worry about a fprintf(stderr). */
265
	if (!int_table_check(table, 0))
266
		goto end;
267
	tmplate.nid = nid;
268
	fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate);
269
	if (!fnd)
270
		goto end;
271
	if (fnd->funct && engine_unlocked_init(fnd->funct)) {
272
#ifdef ENGINE_TABLE_DEBUG
273
		fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
274
		    "ENGINE '%s' cached\n", f, l, nid, fnd->funct->id);
275
#endif
276
		ret = fnd->funct;
277
		goto end;
278
	}
279
	if (fnd->uptodate) {
280
		ret = fnd->funct;
281
		goto end;
282
	}
283
trynext:
284
	ret = sk_ENGINE_value(fnd->sk, loop++);
285
	if (!ret) {
286
#ifdef ENGINE_TABLE_DEBUG
287
		fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no "
288
		    "registered implementations would initialise\n", f, l, nid);
289
#endif
290
		goto end;
291
	}
292
	/* Try to initialise the ENGINE? */
293
	if ((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT))
294
		initres = engine_unlocked_init(ret);
295
	else
296
		initres = 0;
297
	if (initres) {
298
		/* Update 'funct' */
299
		if ((fnd->funct != ret) && engine_unlocked_init(ret)) {
300
			/* If there was a previous default we release it. */
301
			if (fnd->funct)
302
				engine_unlocked_finish(fnd->funct, 0);
303
			fnd->funct = ret;
304
#ifdef ENGINE_TABLE_DEBUG
305
			fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, "
306
			    "setting default to '%s'\n", f, l, nid, ret->id);
307
#endif
308
		}
309
#ifdef ENGINE_TABLE_DEBUG
310
		fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
311
		    "newly initialised '%s'\n", f, l, nid, ret->id);
312
#endif
313
		goto end;
314
	}
315
	goto trynext;
316
end:
317
	/* If it failed, it is unlikely to succeed again until some future
318
	 * registrations have taken place. In all cases, we cache. */
319
	if (fnd)
320
		fnd->uptodate = 1;
321
#ifdef ENGINE_TABLE_DEBUG
322
	if (ret)
323
		fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
324
		    "ENGINE '%s'\n", f, l, nid, ret->id);
325
	else
326
		fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
327
		    "'no matching ENGINE'\n", f, l, nid);
328
#endif
329
	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
330
	/* Whatever happened, any failed init()s are not failures in this
331
	 * context, so clear our error state. */
332
	ERR_pop_to_mark();
333
	return ret;
334
531004
}
335
336
/* Table enumeration */
337
338
static void
339
int_cb_doall_arg(ENGINE_PILE *pile, ENGINE_PILE_DOALL *dall)
340
{
341
	dall->cb(pile->nid, pile->sk, pile->funct, dall->arg);
342
}
343
static IMPLEMENT_LHASH_DOALL_ARG_FN(int_cb, ENGINE_PILE, ENGINE_PILE_DOALL)
344
345
void
346
engine_table_doall(ENGINE_TABLE *table, engine_table_doall_cb *cb, void *arg)
347
{
348
56
	ENGINE_PILE_DOALL dall;
349
350
28
	dall.cb = cb;
351
28
	dall.arg = arg;
352
28
	lh_ENGINE_PILE_doall_arg(&table->piles, LHASH_DOALL_ARG_FN(int_cb),
353
	    ENGINE_PILE_DOALL, &dall);
354
28
}