GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/crypto/../../libssl/src/crypto/engine/eng_table.c Lines: 6 119 5.0 %
Date: 2016-12-06 Branches: 1 66 1.5 %

Line Branch Exec Source
1
/* $OpenBSD: eng_table.c,v 1.8 2015/02/11 03:19:37 doug 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
				ENGINEerr(ENGINE_F_ENGINE_TABLE_REGISTER,
176
				    ENGINE_R_INIT_FAILED);
177
				goto end;
178
			}
179
			if (fnd->funct)
180
				engine_unlocked_finish(fnd->funct, 0);
181
			fnd->funct = e;
182
			fnd->uptodate = 1;
183
		}
184
		nids++;
185
	}
186
	ret = 1;
187
end:
188
	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
189
	return ret;
190
}
191
192
static void
193
int_unregister_cb_doall_arg(ENGINE_PILE *pile, ENGINE *e)
194
{
195
	int n;
196
197
	/* Iterate the 'c->sk' stack removing any occurance of 'e' */
198
	while ((n = sk_ENGINE_find(pile->sk, e)) >= 0) {
199
		(void)sk_ENGINE_delete(pile->sk, n);
200
		pile->uptodate = 0;
201
	}
202
	if (pile->funct == e) {
203
		engine_unlocked_finish(e, 0);
204
		pile->funct = NULL;
205
	}
206
}
207
static IMPLEMENT_LHASH_DOALL_ARG_FN(int_unregister_cb, ENGINE_PILE, ENGINE)
208
209
void
210
engine_table_unregister(ENGINE_TABLE **table, ENGINE *e)
211
{
212
	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
213
	if (int_table_check(table, 0))
214
		lh_ENGINE_PILE_doall_arg(&(*table)->piles,
215
		    LHASH_DOALL_ARG_FN(int_unregister_cb), ENGINE, e);
216
	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
217
}
218
219
static void
220
int_cleanup_cb_doall(ENGINE_PILE *p)
221
{
222
	sk_ENGINE_free(p->sk);
223
	if (p->funct)
224
		engine_unlocked_finish(p->funct, 0);
225
	free(p);
226
}
227
static IMPLEMENT_LHASH_DOALL_FN(int_cleanup_cb, ENGINE_PILE)
228
229
void
230
engine_table_cleanup(ENGINE_TABLE **table)
231
{
232
	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
233
	if (*table) {
234
		lh_ENGINE_PILE_doall(&(*table)->piles,
235
		    LHASH_DOALL_FN(int_cleanup_cb));
236
		lh_ENGINE_PILE_free(&(*table)->piles);
237
		*table = NULL;
238
	}
239
	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
240
}
241
242
/* return a functional reference for a given 'nid' */
243
#ifndef ENGINE_TABLE_DEBUG
244
ENGINE *
245
engine_table_select(ENGINE_TABLE **table, int nid)
246
#else
247
ENGINE *
248
engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f, int l)
249
#endif
250
1744
{
251
1744
	ENGINE *ret = NULL;
252
1744
	ENGINE_PILE tmplate, *fnd = NULL;
253
1744
	int initres, loop = 0;
254
255
1744
	if (!(*table)) {
256
#ifdef ENGINE_TABLE_DEBUG
257
		fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing "
258
		    "registered!\n", f, l, nid);
259
#endif
260
1744
		return NULL;
261
	}
262
	ERR_set_mark();
263
	CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
264
	/* Check again inside the lock otherwise we could race against cleanup
265
	 * operations. But don't worry about a fprintf(stderr). */
266
	if (!int_table_check(table, 0))
267
		goto end;
268
	tmplate.nid = nid;
269
	fnd = lh_ENGINE_PILE_retrieve(&(*table)->piles, &tmplate);
270
	if (!fnd)
271
		goto end;
272
	if (fnd->funct && engine_unlocked_init(fnd->funct)) {
273
#ifdef ENGINE_TABLE_DEBUG
274
		fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
275
		    "ENGINE '%s' cached\n", f, l, nid, fnd->funct->id);
276
#endif
277
		ret = fnd->funct;
278
		goto end;
279
	}
280
	if (fnd->uptodate) {
281
		ret = fnd->funct;
282
		goto end;
283
	}
284
trynext:
285
	ret = sk_ENGINE_value(fnd->sk, loop++);
286
	if (!ret) {
287
#ifdef ENGINE_TABLE_DEBUG
288
		fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no "
289
		    "registered implementations would initialise\n", f, l, nid);
290
#endif
291
		goto end;
292
	}
293
	/* Try to initialise the ENGINE? */
294
	if ((ret->funct_ref > 0) || !(table_flags & ENGINE_TABLE_FLAG_NOINIT))
295
		initres = engine_unlocked_init(ret);
296
	else
297
		initres = 0;
298
	if (initres) {
299
		/* Update 'funct' */
300
		if ((fnd->funct != ret) && engine_unlocked_init(ret)) {
301
			/* If there was a previous default we release it. */
302
			if (fnd->funct)
303
				engine_unlocked_finish(fnd->funct, 0);
304
			fnd->funct = ret;
305
#ifdef ENGINE_TABLE_DEBUG
306
			fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, "
307
			    "setting default to '%s'\n", f, l, nid, ret->id);
308
#endif
309
		}
310
#ifdef ENGINE_TABLE_DEBUG
311
		fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
312
		    "newly initialised '%s'\n", f, l, nid, ret->id);
313
#endif
314
		goto end;
315
	}
316
	goto trynext;
317
end:
318
	/* If it failed, it is unlikely to succeed again until some future
319
	 * registrations have taken place. In all cases, we cache. */
320
	if (fnd)
321
		fnd->uptodate = 1;
322
#ifdef ENGINE_TABLE_DEBUG
323
	if (ret)
324
		fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
325
		    "ENGINE '%s'\n", f, l, nid, ret->id);
326
	else
327
		fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
328
		    "'no matching ENGINE'\n", f, l, nid);
329
#endif
330
	CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
331
	/* Whatever happened, any failed init()s are not failures in this
332
	 * context, so clear our error state. */
333
	ERR_pop_to_mark();
334
	return ret;
335
}
336
337
/* Table enumeration */
338
339
static void
340
int_cb_doall_arg(ENGINE_PILE *pile, ENGINE_PILE_DOALL *dall)
341
{
342
	dall->cb(pile->nid, pile->sk, pile->funct, dall->arg);
343
}
344
static IMPLEMENT_LHASH_DOALL_ARG_FN(int_cb, ENGINE_PILE, ENGINE_PILE_DOALL)
345
346
void
347
engine_table_doall(ENGINE_TABLE *table, engine_table_doall_cb *cb, void *arg)
348
{
349
	ENGINE_PILE_DOALL dall;
350
351
	dall.cb = cb;
352
	dall.arg = arg;
353
	lh_ENGINE_PILE_doall_arg(&table->piles, LHASH_DOALL_ARG_FN(int_cb),
354
	    ENGINE_PILE_DOALL, &dall);
355
}