engine.c revision 160814
1106266Sjulian/* apps/engine.c -*- mode: C; c-file-style: "eay" -*- */
2106266Sjulian/* Written by Richard Levitte <richard@levitte.org> for the OpenSSL
3106266Sjulian * project 2000.
4106266Sjulian */
5106266Sjulian/* ====================================================================
6106266Sjulian * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
7106266Sjulian *
8106266Sjulian * Redistribution and use in source and binary forms, with or without
9106319Sjulian * modification, are permitted provided that the following conditions
10106266Sjulian * are met:
11106319Sjulian *
12106319Sjulian * 1. Redistributions of source code must retain the above copyright
13106266Sjulian *    notice, this list of conditions and the following disclaimer.
14106319Sjulian *
15106319Sjulian * 2. Redistributions in binary form must reproduce the above copyright
16106266Sjulian *    notice, this list of conditions and the following disclaimer in
17106266Sjulian *    the documentation and/or other materials provided with the
18106266Sjulian *    distribution.
19106319Sjulian *
20106319Sjulian * 3. All advertising materials mentioning features or use of this
21106319Sjulian *    software must display the following acknowledgment:
22106266Sjulian *    "This product includes software developed by the OpenSSL Project
23106266Sjulian *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24106266Sjulian *
25106266Sjulian * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26106266Sjulian *    endorse or promote products derived from this software without
27106319Sjulian *    prior written permission. For written permission, please contact
28106266Sjulian *    licensing@OpenSSL.org.
29106266Sjulian *
30106266Sjulian * 5. Products derived from this software may not be called "OpenSSL"
31106266Sjulian *    nor may "OpenSSL" appear in their names without prior written
32106266Sjulian *    permission of the OpenSSL Project.
33106266Sjulian *
34106266Sjulian * 6. Redistributions of any form whatsoever must retain the following
35106266Sjulian *    acknowledgment:
36106266Sjulian *    "This product includes software developed by the OpenSSL Project
37106266Sjulian *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38125077Sharti *
39125077Sharti * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40125077Sharti * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41106266Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42106266Sjulian * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43106266Sjulian * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44106266Sjulian * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45106266Sjulian * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46106266Sjulian * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47106266Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48106266Sjulian * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49106266Sjulian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50106266Sjulian * OF THE POSSIBILITY OF SUCH DAMAGE.
51106266Sjulian * ====================================================================
52106266Sjulian *
53106266Sjulian * This product includes cryptographic software written by Eric Young
54106266Sjulian * (eay@cryptsoft.com).  This product includes software written by Tim
55106266Sjulian * Hudson (tjh@cryptsoft.com).
56106266Sjulian *
57106266Sjulian */
58106266Sjulian
59106266Sjulian#ifndef OPENSSL_NO_ENGINE
60106266Sjulian
61106266Sjulian#include <stdio.h>
62106266Sjulian#include <stdlib.h>
63106266Sjulian#include <string.h>
64106266Sjulian#ifdef OPENSSL_NO_STDIO
65106266Sjulian#define APPS_WIN16
66106266Sjulian#endif
67106266Sjulian#include "apps.h"
68106266Sjulian#include <openssl/err.h>
69106266Sjulian#include <openssl/engine.h>
70106266Sjulian#include <openssl/ssl.h>
71106266Sjulian
72106266Sjulian#undef PROG
73106266Sjulian#define PROG	engine_main
74106266Sjulian
75106266Sjulianstatic const char *engine_usage[]={
76106266Sjulian"usage: engine opts [engine ...]\n",
77106266Sjulian" -v[v[v[v]]] - verbose mode, for each engine, list its 'control commands'\n",
78106266Sjulian"               -vv will additionally display each command's description\n",
79106266Sjulian"               -vvv will also add the input flags for each command\n",
80106266Sjulian"               -vvvv will also show internal input flags\n",
81106266Sjulian" -c          - for each engine, also list the capabilities\n",
82106266Sjulian" -t[t]       - for each engine, check that they are really available\n",
83106266Sjulian"               -tt will display error trace for unavailable engines\n",
84106266Sjulian" -pre <cmd>  - runs command 'cmd' against the ENGINE before any attempts\n",
85106266Sjulian"               to load it (if -t is used)\n",
86106266Sjulian" -post <cmd> - runs command 'cmd' against the ENGINE after loading it\n",
87106266Sjulian"               (only used if -t is also provided)\n",
88106319Sjulian" NB: -pre and -post will be applied to all ENGINEs supplied on the command\n",
89106266Sjulian" line, or all supported ENGINEs if none are specified.\n",
90106266Sjulian" Eg. '-pre \"SO_PATH:/lib/libdriver.so\"' calls command \"SO_PATH\" with\n",
91106319Sjulian" argument \"/lib/libdriver.so\".\n",
92106266SjulianNULL
93106266Sjulian};
94106266Sjulian
95106266Sjulianstatic void identity(void *ptr)
96106266Sjulian	{
97106266Sjulian	return;
98106266Sjulian	}
99106266Sjulian
100106266Sjulianstatic int append_buf(char **buf, const char *s, int *size, int step)
101106266Sjulian	{
102106266Sjulian	int l = strlen(s);
103106266Sjulian
104106266Sjulian	if (*buf == NULL)
105106266Sjulian		{
106106266Sjulian		*size = step;
107106266Sjulian		*buf = OPENSSL_malloc(*size);
108125243Sharti		if (*buf == NULL)
109125029Sharti			return 0;
110106266Sjulian		**buf = '\0';
111106266Sjulian		}
112106266Sjulian
113106266Sjulian	if (**buf != '\0')
114106435Sjulian		l += 2;		/* ", " */
115106435Sjulian
116106266Sjulian	if (strlen(*buf) + strlen(s) >= (unsigned int)*size)
117106266Sjulian		{
118106266Sjulian		*size += step;
119125077Sharti		*buf = OPENSSL_realloc(*buf, *size);
120106266Sjulian		}
121106266Sjulian
122106266Sjulian	if (*buf == NULL)
123106266Sjulian		return 0;
124106266Sjulian
125106266Sjulian	if (**buf != '\0')
126106266Sjulian		BUF_strlcat(*buf, ", ", *size);
127106266Sjulian	BUF_strlcat(*buf, s, *size);
128106266Sjulian
129106266Sjulian	return 1;
130106266Sjulian	}
131106266Sjulian
132106266Sjulianstatic int util_flags(BIO *bio_out, unsigned int flags, const char *indent)
133106266Sjulian	{
134106266Sjulian	int started = 0, err = 0;
135106266Sjulian	/* Indent before displaying input flags */
136106266Sjulian	BIO_printf(bio_out, "%s%s(input flags): ", indent, indent);
137106266Sjulian	if(flags == 0)
138106266Sjulian		{
139106266Sjulian		BIO_printf(bio_out, "<no flags>\n");
140106266Sjulian		return 1;
141106266Sjulian		}
142106266Sjulian        /* If the object is internal, mark it in a way that shows instead of
143106266Sjulian         * having it part of all the other flags, even if it really is. */
144106266Sjulian	if(flags & ENGINE_CMD_FLAG_INTERNAL)
145106266Sjulian		{
146106266Sjulian		BIO_printf(bio_out, "[Internal] ");
147106266Sjulian		}
148106266Sjulian
149106266Sjulian	if(flags & ENGINE_CMD_FLAG_NUMERIC)
150106266Sjulian		{
151106266Sjulian		if(started)
152106266Sjulian			{
153106266Sjulian			BIO_printf(bio_out, "|");
154106266Sjulian			err = 1;
155106266Sjulian			}
156106266Sjulian		BIO_printf(bio_out, "NUMERIC");
157106266Sjulian		started = 1;
158106266Sjulian		}
159106266Sjulian	/* Now we check that no combinations of the mutually exclusive NUMERIC,
160106266Sjulian	 * STRING, and NO_INPUT flags have been used. Future flags that can be
161106266Sjulian	 * OR'd together with these would need to added after these to preserve
162106266Sjulian	 * the testing logic. */
163106266Sjulian	if(flags & ENGINE_CMD_FLAG_STRING)
164106266Sjulian		{
165106266Sjulian		if(started)
166106266Sjulian			{
167106266Sjulian			BIO_printf(bio_out, "|");
168106266Sjulian			err = 1;
169106266Sjulian			}
170106266Sjulian		BIO_printf(bio_out, "STRING");
171106266Sjulian		started = 1;
172106266Sjulian		}
173106266Sjulian	if(flags & ENGINE_CMD_FLAG_NO_INPUT)
174106266Sjulian		{
175106266Sjulian		if(started)
176106266Sjulian			{
177106266Sjulian			BIO_printf(bio_out, "|");
178106266Sjulian			err = 1;
179106266Sjulian			}
180106266Sjulian		BIO_printf(bio_out, "NO_INPUT");
181125033Sharti		started = 1;
182125033Sharti		}
183125033Sharti	/* Check for unknown flags */
184125033Sharti	flags = flags & ~ENGINE_CMD_FLAG_NUMERIC &
185125033Sharti			~ENGINE_CMD_FLAG_STRING &
186125033Sharti			~ENGINE_CMD_FLAG_NO_INPUT &
187125033Sharti			~ENGINE_CMD_FLAG_INTERNAL;
188106266Sjulian	if(flags)
189106266Sjulian		{
190106266Sjulian		if(started) BIO_printf(bio_out, "|");
191106266Sjulian		BIO_printf(bio_out, "<0x%04X>", flags);
192106266Sjulian		}
193125029Sharti	if(err)
194106266Sjulian		BIO_printf(bio_out, "  <illegal flags!>");
195106266Sjulian	BIO_printf(bio_out, "\n");
196106266Sjulian	return 1;
197106266Sjulian	}
198106266Sjulian
199106266Sjulianstatic int util_verbose(ENGINE *e, int verbose, BIO *bio_out, const char *indent)
200106266Sjulian	{
201125077Sharti	static const int line_wrap = 78;
202106266Sjulian	int num;
203106266Sjulian	int ret = 0;
204106266Sjulian	char *name = NULL;
205106266Sjulian	char *desc = NULL;
206106266Sjulian	int flags;
207106266Sjulian	int xpos = 0;
208125032Sharti	STACK *cmds = NULL;
209125032Sharti	if(!ENGINE_ctrl(e, ENGINE_CTRL_HAS_CTRL_FUNCTION, 0, NULL, NULL) ||
210106266Sjulian			((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE,
211106266Sjulian					0, NULL, NULL)) <= 0))
212106266Sjulian		{
213106266Sjulian#if 0
214106321Sjulian		BIO_printf(bio_out, "%s<no control commands>\n", indent);
215106266Sjulian#endif
216106266Sjulian		return 1;
217106266Sjulian		}
218125030Sharti
219106266Sjulian	cmds = sk_new_null();
220106266Sjulian
221106266Sjulian	if(!cmds)
222106321Sjulian		goto err;
223106321Sjulian	do {
224106266Sjulian		int len;
225106321Sjulian		/* Get the command input flags */
226106321Sjulian		if((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num,
227106266Sjulian					NULL, NULL)) < 0)
228106266Sjulian			goto err;
229106266Sjulian                if (!(flags & ENGINE_CMD_FLAG_INTERNAL) || verbose >= 4)
230106266Sjulian                        {
231106266Sjulian                        /* Get the command name */
232106266Sjulian                        if((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD, num,
233106266Sjulian                                NULL, NULL)) <= 0)
234106266Sjulian                                goto err;
235106266Sjulian                        if((name = OPENSSL_malloc(len + 1)) == NULL)
236106321Sjulian                                goto err;
237106266Sjulian                        if(ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_FROM_CMD, num, name,
238106321Sjulian                                NULL) <= 0)
239125077Sharti                                goto err;
240106266Sjulian                        /* Get the command description */
241106266Sjulian                        if((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD, num,
242106321Sjulian                                NULL, NULL)) < 0)
243106266Sjulian                                goto err;
244106266Sjulian                        if(len > 0)
245106321Sjulian                                {
246106266Sjulian                                if((desc = OPENSSL_malloc(len + 1)) == NULL)
247106266Sjulian                                        goto err;
248106266Sjulian                                if(ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_FROM_CMD, num, desc,
249106266Sjulian                                        NULL) <= 0)
250106266Sjulian                                        goto err;
251106266Sjulian                                }
252106266Sjulian                        /* Now decide on the output */
253106266Sjulian                        if(xpos == 0)
254106266Sjulian                                /* Do an indent */
255106266Sjulian                                xpos = BIO_printf(bio_out, indent);
256106266Sjulian                        else
257106321Sjulian                                /* Otherwise prepend a ", " */
258106266Sjulian                                xpos += BIO_printf(bio_out, ", ");
259106321Sjulian                        if(verbose == 1)
260106266Sjulian                                {
261106266Sjulian                                /* We're just listing names, comma-delimited */
262106321Sjulian                                if((xpos > (int)strlen(indent)) &&
263106266Sjulian					(xpos + (int)strlen(name) > line_wrap))
264106321Sjulian                                        {
265106321Sjulian                                        BIO_printf(bio_out, "\n");
266125077Sharti                                        xpos = BIO_printf(bio_out, indent);
267106266Sjulian                                        }
268106266Sjulian                                xpos += BIO_printf(bio_out, "%s", name);
269106435Sjulian                                }
270106435Sjulian                        else
271106435Sjulian                                {
272106435Sjulian                                /* We're listing names plus descriptions */
273106266Sjulian                                BIO_printf(bio_out, "%s: %s\n", name,
274106266Sjulian                                        (desc == NULL) ? "<no description>" : desc);
275106266Sjulian                                /* ... and sometimes input flags */
276106266Sjulian                                if((verbose >= 3) && !util_flags(bio_out, flags,
277106266Sjulian                                        indent))
278106266Sjulian                                        goto err;
279106266Sjulian                                xpos = 0;
280106266Sjulian                                }
281106266Sjulian                        }
282106266Sjulian		OPENSSL_free(name); name = NULL;
283106266Sjulian		if(desc) { OPENSSL_free(desc); desc = NULL; }
284106266Sjulian		/* Move to the next command */
285106266Sjulian		num = ENGINE_ctrl(e, ENGINE_CTRL_GET_NEXT_CMD_TYPE,
286106266Sjulian					num, NULL, NULL);
287106266Sjulian		} while(num > 0);
288106319Sjulian	if(xpos > 0)
289106321Sjulian		BIO_printf(bio_out, "\n");
290106266Sjulian	ret = 1;
291106319Sjulianerr:
292106266Sjulian	if(cmds) sk_pop_free(cmds, identity);
293106319Sjulian	if(name) OPENSSL_free(name);
294106266Sjulian	if(desc) OPENSSL_free(desc);
295106319Sjulian	return ret;
296106266Sjulian	}
297106266Sjulian
298106266Sjulianstatic void util_do_cmds(ENGINE *e, STACK *cmds, BIO *bio_out, const char *indent)
299106266Sjulian	{
300106266Sjulian	int loop, res, num = sk_num(cmds);
301106266Sjulian	if(num < 0)
302106266Sjulian		{
303106266Sjulian		BIO_printf(bio_out, "[Error]: internal stack error\n");
304106266Sjulian		return;
305106266Sjulian		}
306106319Sjulian	for(loop = 0; loop < num; loop++)
307125077Sharti		{
308106266Sjulian		char buf[256];
309106266Sjulian		const char *cmd, *arg;
310106266Sjulian		cmd = sk_value(cmds, loop);
311106266Sjulian		res = 1; /* assume success */
312106266Sjulian		/* Check if this command has no ":arg" */
313106266Sjulian		if((arg = strstr(cmd, ":")) == NULL)
314106266Sjulian			{
315106266Sjulian			if(!ENGINE_ctrl_cmd_string(e, cmd, NULL, 0))
316125033Sharti				res = 0;
317125033Sharti			}
318125033Sharti		else
319125033Sharti			{
320125033Sharti			if((int)(arg - cmd) > 254)
321125077Sharti				{
322125033Sharti				BIO_printf(bio_out,"[Error]: command name too long\n");
323125033Sharti				return;
324125033Sharti				}
325125033Sharti			memcpy(buf, cmd, (int)(arg - cmd));
326125033Sharti			buf[arg-cmd] = '\0';
327125033Sharti			arg++; /* Move past the ":" */
328125033Sharti			/* Call the command with the argument */
329125033Sharti			if(!ENGINE_ctrl_cmd_string(e, buf, arg, 0))
330125033Sharti				res = 0;
331125033Sharti			}
332125033Sharti		if(res)
333125033Sharti			BIO_printf(bio_out, "[Success]: %s\n", cmd);
334125033Sharti		else
335125033Sharti			{
336125033Sharti			BIO_printf(bio_out, "[Failure]: %s\n", cmd);
337125243Sharti			ERR_print_errors(bio_out);
338125243Sharti			}
339125033Sharti		}
340125033Sharti	}
341106266Sjulian
342106266Sjulianint MAIN(int, char **);
343106266Sjulian
344106266Sjulianint MAIN(int argc, char **argv)
345106266Sjulian	{
346106266Sjulian	int ret=1,i;
347106266Sjulian	const char **pp;
348106266Sjulian	int verbose=0, list_cap=0, test_avail=0, test_avail_noise = 0;
349106266Sjulian	ENGINE *e;
350106266Sjulian	STACK *engines = sk_new_null();
351106266Sjulian	STACK *pre_cmds = sk_new_null();
352106435Sjulian	STACK *post_cmds = sk_new_null();
353106435Sjulian	int badops=1;
354106435Sjulian	BIO *bio_out=NULL;
355106435Sjulian	const char *indent = "     ";
356106435Sjulian
357106435Sjulian	apps_startup();
358106435Sjulian	SSL_load_error_strings();
359106435Sjulian
360106435Sjulian	if (bio_err == NULL)
361106435Sjulian		bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
362106435Sjulian
363106435Sjulian	if (!load_config(bio_err, NULL))
364106435Sjulian		goto end;
365125243Sharti	bio_out=BIO_new_fp(stdout,BIO_NOCLOSE);
366125243Sharti#ifdef OPENSSL_SYS_VMS
367106435Sjulian	{
368106435Sjulian	BIO *tmpbio = BIO_new(BIO_f_linebuffer());
369106435Sjulian	bio_out = BIO_push(tmpbio, bio_out);
370106435Sjulian	}
371106435Sjulian#endif
372106435Sjulian
373106266Sjulian	argc--;
374106266Sjulian	argv++;
375106266Sjulian	while (argc >= 1)
376106266Sjulian		{
377106266Sjulian		if (strncmp(*argv,"-v",2) == 0)
378106266Sjulian			{
379106321Sjulian			if(strspn(*argv + 1, "v") < strlen(*argv + 1))
380106321Sjulian				goto skip_arg_loop;
381106321Sjulian			if((verbose=strlen(*argv + 1)) > 4)
382106321Sjulian				goto skip_arg_loop;
383106266Sjulian			}
384106266Sjulian		else if (strcmp(*argv,"-c") == 0)
385106266Sjulian			list_cap=1;
386106266Sjulian		else if (strncmp(*argv,"-t",2) == 0)
387106266Sjulian			{
388106266Sjulian			test_avail=1;
389106266Sjulian			if(strspn(*argv + 1, "t") < strlen(*argv + 1))
390106266Sjulian				goto skip_arg_loop;
391106266Sjulian			if((test_avail_noise = strlen(*argv + 1) - 1) > 1)
392106266Sjulian				goto skip_arg_loop;
393106321Sjulian			}
394106266Sjulian		else if (strcmp(*argv,"-pre") == 0)
395106321Sjulian			{
396106321Sjulian			argc--; argv++;
397106266Sjulian			if (argc == 0)
398106321Sjulian				goto skip_arg_loop;
399106266Sjulian			sk_push(pre_cmds,*argv);
400106321Sjulian			}
401106321Sjulian		else if (strcmp(*argv,"-post") == 0)
402106321Sjulian			{
403106321Sjulian			argc--; argv++;
404125077Sharti			if (argc == 0)
405125077Sharti				goto skip_arg_loop;
406106266Sjulian			sk_push(post_cmds,*argv);
407106266Sjulian			}
408106266Sjulian		else if ((strncmp(*argv,"-h",2) == 0) ||
409106266Sjulian				(strcmp(*argv,"-?") == 0))
410106321Sjulian			goto skip_arg_loop;
411106266Sjulian		else
412106266Sjulian			sk_push(engines,*argv);
413125077Sharti		argc--;
414106266Sjulian		argv++;
415106266Sjulian		}
416125077Sharti	/* Looks like everything went OK */
417106321Sjulian	badops = 0;
418106266Sjulianskip_arg_loop:
419106266Sjulian
420106266Sjulian	if (badops)
421106266Sjulian		{
422106266Sjulian		for (pp=engine_usage; (*pp != NULL); pp++)
423125031Sharti			BIO_printf(bio_err,"%s",*pp);
424106266Sjulian		goto end;
425106266Sjulian		}
426106266Sjulian
427106266Sjulian	if (sk_num(engines) == 0)
428106266Sjulian		{
429106266Sjulian		for(e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e))
430106266Sjulian			{
431106266Sjulian			sk_push(engines,(char *)ENGINE_get_id(e));
432106266Sjulian			}
433106266Sjulian		}
434106266Sjulian
435106321Sjulian	for (i=0; i<sk_num(engines); i++)
436106266Sjulian		{
437106321Sjulian		const char *id = sk_value(engines,i);
438125077Sharti		if ((e = ENGINE_by_id(id)) != NULL)
439106321Sjulian			{
440106266Sjulian			const char *name = ENGINE_get_name(e);
441106266Sjulian			/* Do "id" first, then "name". Easier to auto-parse. */
442106321Sjulian			BIO_printf(bio_out, "(%s) %s\n", id, name);
443106321Sjulian			util_do_cmds(e, pre_cmds, bio_out, indent);
444125077Sharti			if (strcmp(ENGINE_get_id(e), id) != 0)
445106266Sjulian				{
446106266Sjulian				BIO_printf(bio_out, "Loaded: (%s) %s\n",
447106266Sjulian					ENGINE_get_id(e), ENGINE_get_name(e));
448106266Sjulian				}
449106266Sjulian			if (list_cap)
450106266Sjulian				{
451106266Sjulian				int cap_size = 256;
452106266Sjulian				char *cap_buf = NULL;
453106266Sjulian				int k,n;
454106321Sjulian				const int *nids;
455106319Sjulian				ENGINE_CIPHERS_PTR fn_c;
456106266Sjulian				ENGINE_DIGESTS_PTR fn_d;
457106321Sjulian
458106321Sjulian				if (ENGINE_get_RSA(e) != NULL
459125077Sharti					&& !append_buf(&cap_buf, "RSA",
460106266Sjulian						&cap_size, 256))
461106321Sjulian					goto end;
462106321Sjulian				if (ENGINE_get_DSA(e) != NULL
463106266Sjulian					&& !append_buf(&cap_buf, "DSA",
464106266Sjulian						&cap_size, 256))
465106266Sjulian					goto end;
466106266Sjulian				if (ENGINE_get_DH(e) != NULL
467106435Sjulian					&& !append_buf(&cap_buf, "DH",
468106435Sjulian						&cap_size, 256))
469106435Sjulian					goto end;
470106266Sjulian				if (ENGINE_get_RAND(e) != NULL
471125029Sharti					&& !append_buf(&cap_buf, "RAND",
472106435Sjulian						&cap_size, 256))
473106266Sjulian					goto end;
474106435Sjulian
475106266Sjulian				fn_c = ENGINE_get_ciphers(e);
476106266Sjulian				if(!fn_c) goto skip_ciphers;
477106266Sjulian				n = fn_c(e, NULL, &nids, 0);
478106266Sjulian				for(k=0 ; k < n ; ++k)
479106266Sjulian					if(!append_buf(&cap_buf,
480106319Sjulian						       OBJ_nid2sn(nids[k]),
481106266Sjulian						       &cap_size, 256))
482106266Sjulian						goto end;
483106266Sjulian
484125078Shartiskip_ciphers:
485106435Sjulian				fn_d = ENGINE_get_digests(e);
486106435Sjulian				if(!fn_d) goto skip_digests;
487106266Sjulian				n = fn_d(e, NULL, &nids, 0);
488106435Sjulian				for(k=0 ; k < n ; ++k)
489106435Sjulian					if(!append_buf(&cap_buf,
490106435Sjulian						       OBJ_nid2sn(nids[k]),
491106435Sjulian						       &cap_size, 256))
492106435Sjulian						goto end;
493106435Sjulian
494106435Sjulianskip_digests:
495106435Sjulian				if (cap_buf && (*cap_buf != '\0'))
496106435Sjulian					BIO_printf(bio_out, " [%s]\n", cap_buf);
497106435Sjulian
498106266Sjulian				OPENSSL_free(cap_buf);
499106435Sjulian				}
500106266Sjulian			if(test_avail)
501106266Sjulian				{
502106435Sjulian				BIO_printf(bio_out, "%s", indent);
503106266Sjulian				if (ENGINE_init(e))
504106266Sjulian					{
505106266Sjulian					BIO_printf(bio_out, "[ available ]\n");
506106266Sjulian					util_do_cmds(e, post_cmds, bio_out, indent);
507108172Shsu					ENGINE_finish(e);
508106266Sjulian					}
509106266Sjulian				else
510106266Sjulian					{
511106266Sjulian					BIO_printf(bio_out, "[ unavailable ]\n");
512108172Shsu					if(test_avail_noise)
513106266Sjulian						ERR_print_errors_fp(stdout);
514106266Sjulian					ERR_clear_error();
515125077Sharti					}
516106266Sjulian				}
517106266Sjulian			if((verbose > 0) && !util_verbose(e, verbose, bio_out, indent))
518106266Sjulian				goto end;
519106266Sjulian			ENGINE_free(e);
520106266Sjulian			}
521106266Sjulian		else
522106266Sjulian			ERR_print_errors(bio_err);
523106266Sjulian		}
524106266Sjulian
525106266Sjulian	ret=0;
526106266Sjulianend:
527125077Sharti
528106266Sjulian	ERR_print_errors(bio_err);
529106319Sjulian	sk_pop_free(engines, identity);
530106266Sjulian	sk_pop_free(pre_cmds, identity);
531106266Sjulian	sk_pop_free(post_cmds, identity);
532106266Sjulian	if (bio_out != NULL) BIO_free_all(bio_out);
533106266Sjulian	apps_shutdown();
534106266Sjulian	OPENSSL_EXIT(ret);
535106266Sjulian	}
536106266Sjulian#else
537106266Sjulian
538106266Sjulian# if PEDANTIC
539106266Sjulianstatic void *dummy=&dummy;
540106266Sjulian# endif
541106266Sjulian
542106266Sjulian#endif
543106266Sjulian