xref: /freebsd/crypto/openssl/apps/openssl.c (revision 41466b50c1d5bfd1cf6adaae547a579a75d7c04e)
1 /* apps/openssl.c */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  *
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  *
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  *
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  *
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58 
59 #include <stdio.h>
60 #include <string.h>
61 #include <stdlib.h>
62 #define OPENSSL_C /* tells apps.h to use complete apps_startup() */
63 #include <openssl/bio.h>
64 #include <openssl/crypto.h>
65 #include <openssl/lhash.h>
66 #include <openssl/conf.h>
67 #include <openssl/x509.h>
68 #include <openssl/pem.h>
69 #include <openssl/ssl.h>
70 #define USE_SOCKETS /* needed for the _O_BINARY defs in the MS world */
71 #include "apps.h"
72 #include "progs.h"
73 #include "s_apps.h"
74 #include <openssl/err.h>
75 
76 static unsigned long MS_CALLBACK hash(FUNCTION *a);
77 static int MS_CALLBACK cmp(FUNCTION *a,FUNCTION *b);
78 static LHASH *prog_init(void );
79 static int do_cmd(LHASH *prog,int argc,char *argv[]);
80 LHASH *config=NULL;
81 char *default_config_file=NULL;
82 
83 /* Make sure there is only one when MONOLITH is defined */
84 #ifdef MONOLITH
85 BIO *bio_err=NULL;
86 #endif
87 
88 int main(int Argc, char *Argv[])
89 	{
90 	ARGS arg;
91 #define PROG_NAME_SIZE	16
92 	char pname[PROG_NAME_SIZE];
93 	FUNCTION f,*fp;
94 	MS_STATIC char *prompt,buf[1024],config_name[256];
95 	int n,i,ret=0;
96 	int argc;
97 	char **argv,*p;
98 	LHASH *prog=NULL;
99 	long errline;
100 
101 	arg.data=NULL;
102 	arg.count=0;
103 
104 	if (getenv("OPENSSL_DEBUG_MEMORY") != NULL)
105 		CRYPTO_malloc_debug_init();
106 	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
107 
108 	apps_startup();
109 
110 	if (bio_err == NULL)
111 		if ((bio_err=BIO_new(BIO_s_file())) != NULL)
112 			BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
113 
114 	ERR_load_crypto_strings();
115 
116 	/* Lets load up our environment a little */
117 	p=getenv("OPENSSL_CONF");
118 	if (p == NULL)
119 		p=getenv("SSLEAY_CONF");
120 	if (p == NULL)
121 		{
122 		strcpy(config_name,X509_get_default_cert_area());
123 #ifndef VMS
124 		strcat(config_name,"/");
125 #endif
126 		strcat(config_name,OPENSSL_CONF);
127 		p=config_name;
128 		}
129 
130 	default_config_file=p;
131 
132 	config=CONF_load(config,p,&errline);
133 	if (config == NULL) ERR_clear_error();
134 
135 	prog=prog_init();
136 
137 	/* first check the program name */
138 	program_name(Argv[0],pname,PROG_NAME_SIZE);
139 
140 	f.name=pname;
141 	fp=(FUNCTION *)lh_retrieve(prog,&f);
142 	if (fp != NULL)
143 		{
144 		Argv[0]=pname;
145 		ret=fp->func(Argc,Argv);
146 		goto end;
147 		}
148 
149 	/* ok, now check that there are not arguments, if there are,
150 	 * run with them, shifting the ssleay off the front */
151 	if (Argc != 1)
152 		{
153 		Argc--;
154 		Argv++;
155 		ret=do_cmd(prog,Argc,Argv);
156 		if (ret < 0) ret=0;
157 		goto end;
158 		}
159 
160 	/* ok, lets enter the old 'OpenSSL>' mode */
161 
162 	for (;;)
163 		{
164 		ret=0;
165 		p=buf;
166 		n=1024;
167 		i=0;
168 		for (;;)
169 			{
170 			p[0]='\0';
171 			if (i++)
172 				prompt=">";
173 			else	prompt="OpenSSL> ";
174 			fputs(prompt,stdout);
175 			fflush(stdout);
176 			fgets(p,n,stdin);
177 			if (p[0] == '\0') goto end;
178 			i=strlen(p);
179 			if (i <= 1) break;
180 			if (p[i-2] != '\\') break;
181 			i-=2;
182 			p+=i;
183 			n-=i;
184 			}
185 		if (!chopup_args(&arg,buf,&argc,&argv)) break;
186 
187 		ret=do_cmd(prog,argc,argv);
188 		if (ret < 0)
189 			{
190 			ret=0;
191 			goto end;
192 			}
193 		if (ret != 0)
194 			BIO_printf(bio_err,"error in %s\n",argv[0]);
195 		(void)BIO_flush(bio_err);
196 		}
197 	BIO_printf(bio_err,"bad exit\n");
198 	ret=1;
199 end:
200 	if (config != NULL)
201 		{
202 		CONF_free(config);
203 		config=NULL;
204 		}
205 	if (prog != NULL) lh_free(prog);
206 	if (arg.data != NULL) OPENSSL_free(arg.data);
207 	ERR_remove_state(0);
208 
209 	EVP_cleanup();
210 	ERR_free_strings();
211 
212 	CRYPTO_mem_leaks(bio_err);
213 	if (bio_err != NULL)
214 		{
215 		BIO_free(bio_err);
216 		bio_err=NULL;
217 		}
218 	EXIT(ret);
219 	}
220 
221 #define LIST_STANDARD_COMMANDS "list-standard-commands"
222 #define LIST_MESSAGE_DIGEST_COMMANDS "list-message-digest-commands"
223 #define LIST_CIPHER_COMMANDS "list-cipher-commands"
224 
225 static int do_cmd(LHASH *prog, int argc, char *argv[])
226 	{
227 	FUNCTION f,*fp;
228 	int i,ret=1,tp,nl;
229 
230 	if ((argc <= 0) || (argv[0] == NULL))
231 		{ ret=0; goto end; }
232 	f.name=argv[0];
233 	fp=(FUNCTION *)lh_retrieve(prog,&f);
234 	if (fp != NULL)
235 		{
236 		ret=fp->func(argc,argv);
237 		}
238 	else if ((strncmp(argv[0],"no-",3)) == 0)
239 		{
240 		BIO *bio_stdout = BIO_new_fp(stdout,BIO_NOCLOSE);
241 #ifdef VMS
242 		{
243 		BIO *tmpbio = BIO_new(BIO_f_linebuffer());
244 		bio_stdout = BIO_push(tmpbio, bio_stdout);
245 		}
246 #endif
247 		f.name=argv[0]+3;
248 		ret = (lh_retrieve(prog,&f) != NULL);
249 		if (!ret)
250 			BIO_printf(bio_stdout, "%s\n", argv[0]);
251 		else
252 			BIO_printf(bio_stdout, "%s\n", argv[0]+3);
253 		BIO_free_all(bio_stdout);
254 		goto end;
255 		}
256 	else if ((strcmp(argv[0],"quit") == 0) ||
257 		(strcmp(argv[0],"q") == 0) ||
258 		(strcmp(argv[0],"exit") == 0) ||
259 		(strcmp(argv[0],"bye") == 0))
260 		{
261 		ret= -1;
262 		goto end;
263 		}
264 	else if ((strcmp(argv[0],LIST_STANDARD_COMMANDS) == 0) ||
265 		(strcmp(argv[0],LIST_MESSAGE_DIGEST_COMMANDS) == 0) ||
266 		(strcmp(argv[0],LIST_CIPHER_COMMANDS) == 0))
267 		{
268 		int list_type;
269 		BIO *bio_stdout;
270 
271 		if (strcmp(argv[0],LIST_STANDARD_COMMANDS) == 0)
272 			list_type = FUNC_TYPE_GENERAL;
273 		else if (strcmp(argv[0],LIST_MESSAGE_DIGEST_COMMANDS) == 0)
274 			list_type = FUNC_TYPE_MD;
275 		else /* strcmp(argv[0],LIST_CIPHER_COMMANDS) == 0 */
276 			list_type = FUNC_TYPE_CIPHER;
277 		bio_stdout = BIO_new_fp(stdout,BIO_NOCLOSE);
278 #ifdef VMS
279 		{
280 		BIO *tmpbio = BIO_new(BIO_f_linebuffer());
281 		bio_stdout = BIO_push(tmpbio, bio_stdout);
282 		}
283 #endif
284 
285 		for (fp=functions; fp->name != NULL; fp++)
286 			if (fp->type == list_type)
287 				BIO_printf(bio_stdout, "%s\n", fp->name);
288 		BIO_free_all(bio_stdout);
289 		ret=0;
290 		goto end;
291 		}
292 	else
293 		{
294 		BIO_printf(bio_err,"openssl:Error: '%s' is an invalid command.\n",
295 			argv[0]);
296 		BIO_printf(bio_err, "\nStandard commands");
297 		i=0;
298 		tp=0;
299 		for (fp=functions; fp->name != NULL; fp++)
300 			{
301 			nl=0;
302 			if (((i++) % 5) == 0)
303 				{
304 				BIO_printf(bio_err,"\n");
305 				nl=1;
306 				}
307 			if (fp->type != tp)
308 				{
309 				tp=fp->type;
310 				if (!nl) BIO_printf(bio_err,"\n");
311 				if (tp == FUNC_TYPE_MD)
312 					{
313 					i=1;
314 					BIO_printf(bio_err,
315 						"\nMessage Digest commands (see the `dgst' command for more details)\n");
316 					}
317 				else if (tp == FUNC_TYPE_CIPHER)
318 					{
319 					i=1;
320 					BIO_printf(bio_err,"\nCipher commands (see the `enc' command for more details)\n");
321 					}
322 				}
323 			BIO_printf(bio_err,"%-15s",fp->name);
324 			}
325 		BIO_printf(bio_err,"\n\n");
326 		ret=0;
327 		}
328 end:
329 	return(ret);
330 	}
331 
332 static int SortFnByName(const void *_f1,const void *_f2)
333     {
334     const FUNCTION *f1=_f1;
335     const FUNCTION *f2=_f2;
336 
337     if(f1->type != f2->type)
338 	return f1->type-f2->type;
339     return strcmp(f1->name,f2->name);
340     }
341 
342 static LHASH *prog_init(void)
343 	{
344 	LHASH *ret;
345 	FUNCTION *f;
346 	int i;
347 
348 	/* Purely so it looks nice when the user hits ? */
349 	for(i=0,f=functions ; f->name != NULL ; ++f,++i)
350 	    ;
351 	qsort(functions,i,sizeof *functions,SortFnByName);
352 
353 	if ((ret=lh_new(hash,cmp)) == NULL) return(NULL);
354 
355 	for (f=functions; f->name != NULL; f++)
356 		lh_insert(ret,f);
357 	return(ret);
358 	}
359 
360 static int MS_CALLBACK cmp(FUNCTION *a, FUNCTION *b)
361 	{
362 	return(strncmp(a->name,b->name,8));
363 	}
364 
365 static unsigned long MS_CALLBACK hash(FUNCTION *a)
366 	{
367 	return(lh_strhash(a->name));
368 	}
369