dgst.c revision 127128
1/* apps/dgst.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#include "apps.h"
63#include <openssl/bio.h>
64#include <openssl/err.h>
65#include <openssl/evp.h>
66#include <openssl/objects.h>
67#include <openssl/x509.h>
68#include <openssl/pem.h>
69
70#undef BUFSIZE
71#define BUFSIZE	1024*8
72
73#undef PROG
74#define PROG	dgst_main
75
76int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout,
77	  EVP_PKEY *key, unsigned char *sigin, int siglen, const char *title,
78	  const char *file);
79
80int MAIN(int, char **);
81
82int MAIN(int argc, char **argv)
83	{
84	ENGINE *e = NULL;
85	unsigned char *buf=NULL;
86	int i,err=0;
87	const EVP_MD *md=NULL,*m;
88	BIO *in=NULL,*inp;
89	BIO *bmd=NULL;
90	BIO *out = NULL;
91	const char *name;
92#define PROG_NAME_SIZE  39
93	char pname[PROG_NAME_SIZE+1];
94	int separator=0;
95	int debug=0;
96	int keyform=FORMAT_PEM;
97	const char *outfile = NULL, *keyfile = NULL;
98	const char *sigfile = NULL, *randfile = NULL;
99	int out_bin = -1, want_pub = 0, do_verify = 0;
100	EVP_PKEY *sigkey = NULL;
101	unsigned char *sigbuf = NULL;
102	int siglen = 0;
103#ifndef OPENSSL_NO_ENGINE
104	char *engine=NULL;
105#endif
106
107	apps_startup();
108
109	if ((buf=(unsigned char *)OPENSSL_malloc(BUFSIZE)) == NULL)
110		{
111		BIO_printf(bio_err,"out of memory\n");
112		goto end;
113		}
114	if (bio_err == NULL)
115		if ((bio_err=BIO_new(BIO_s_file())) != NULL)
116			BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
117
118	if (!load_config(bio_err, NULL))
119		goto end;
120
121	/* first check the program name */
122	program_name(argv[0],pname,sizeof pname);
123
124	md=EVP_get_digestbyname(pname);
125
126	argc--;
127	argv++;
128	while (argc > 0)
129		{
130		if ((*argv)[0] != '-') break;
131		if (strcmp(*argv,"-c") == 0)
132			separator=1;
133		else if (strcmp(*argv,"-rand") == 0)
134			{
135			if (--argc < 1) break;
136			randfile=*(++argv);
137			}
138		else if (strcmp(*argv,"-out") == 0)
139			{
140			if (--argc < 1) break;
141			outfile=*(++argv);
142			}
143		else if (strcmp(*argv,"-sign") == 0)
144			{
145			if (--argc < 1) break;
146			keyfile=*(++argv);
147			}
148		else if (strcmp(*argv,"-verify") == 0)
149			{
150			if (--argc < 1) break;
151			keyfile=*(++argv);
152			want_pub = 1;
153			do_verify = 1;
154			}
155		else if (strcmp(*argv,"-prverify") == 0)
156			{
157			if (--argc < 1) break;
158			keyfile=*(++argv);
159			do_verify = 1;
160			}
161		else if (strcmp(*argv,"-signature") == 0)
162			{
163			if (--argc < 1) break;
164			sigfile=*(++argv);
165			}
166		else if (strcmp(*argv,"-keyform") == 0)
167			{
168			if (--argc < 1) break;
169			keyform=str2fmt(*(++argv));
170			}
171#ifndef OPENSSL_NO_ENGINE
172		else if (strcmp(*argv,"-engine") == 0)
173			{
174			if (--argc < 1) break;
175			engine= *(++argv);
176			}
177#endif
178		else if (strcmp(*argv,"-hex") == 0)
179			out_bin = 0;
180		else if (strcmp(*argv,"-binary") == 0)
181			out_bin = 1;
182		else if (strcmp(*argv,"-d") == 0)
183			debug=1;
184		else if ((m=EVP_get_digestbyname(&((*argv)[1]))) != NULL)
185			md=m;
186		else
187			break;
188		argc--;
189		argv++;
190		}
191
192	if (md == NULL)
193		md=EVP_md5();
194
195	if(do_verify && !sigfile) {
196		BIO_printf(bio_err, "No signature to verify: use the -signature option\n");
197		err = 1;
198		goto end;
199	}
200
201	if ((argc > 0) && (argv[0][0] == '-')) /* bad option */
202		{
203		BIO_printf(bio_err,"unknown option '%s'\n",*argv);
204		BIO_printf(bio_err,"options are\n");
205		BIO_printf(bio_err,"-c              to output the digest with separating colons\n");
206		BIO_printf(bio_err,"-d              to output debug info\n");
207		BIO_printf(bio_err,"-hex            output as hex dump\n");
208		BIO_printf(bio_err,"-binary         output in binary form\n");
209		BIO_printf(bio_err,"-sign   file    sign digest using private key in file\n");
210		BIO_printf(bio_err,"-verify file    verify a signature using public key in file\n");
211		BIO_printf(bio_err,"-prverify file  verify a signature using private key in file\n");
212		BIO_printf(bio_err,"-keyform arg    key file format (PEM or ENGINE)\n");
213		BIO_printf(bio_err,"-signature file signature to verify\n");
214		BIO_printf(bio_err,"-binary         output in binary form\n");
215#ifndef OPENSSL_NO_ENGINE
216		BIO_printf(bio_err,"-engine e       use engine e, possibly a hardware device.\n");
217#endif
218
219		BIO_printf(bio_err,"-%3s to use the %s message digest algorithm (default)\n",
220			LN_md5,LN_md5);
221		BIO_printf(bio_err,"-%3s to use the %s message digest algorithm\n",
222			LN_md4,LN_md4);
223		BIO_printf(bio_err,"-%3s to use the %s message digest algorithm\n",
224			LN_md2,LN_md2);
225		BIO_printf(bio_err,"-%3s to use the %s message digest algorithm\n",
226			LN_sha1,LN_sha1);
227		BIO_printf(bio_err,"-%3s to use the %s message digest algorithm\n",
228			LN_sha,LN_sha);
229		BIO_printf(bio_err,"-%3s to use the %s message digest algorithm\n",
230			LN_mdc2,LN_mdc2);
231		BIO_printf(bio_err,"-%3s to use the %s message digest algorithm\n",
232			LN_ripemd160,LN_ripemd160);
233		err=1;
234		goto end;
235		}
236
237#ifndef OPENSSL_NO_ENGINE
238        e = setup_engine(bio_err, engine, 0);
239#endif
240
241	in=BIO_new(BIO_s_file());
242	bmd=BIO_new(BIO_f_md());
243	if (debug)
244		{
245		BIO_set_callback(in,BIO_debug_callback);
246		/* needed for windows 3.1 */
247		BIO_set_callback_arg(in,bio_err);
248		}
249
250	if ((in == NULL) || (bmd == NULL))
251		{
252		ERR_print_errors(bio_err);
253		goto end;
254		}
255
256	if(out_bin == -1) {
257		if(keyfile) out_bin = 1;
258		else out_bin = 0;
259	}
260
261	if(randfile)
262		app_RAND_load_file(randfile, bio_err, 0);
263
264	if(outfile) {
265		if(out_bin)
266			out = BIO_new_file(outfile, "wb");
267		else    out = BIO_new_file(outfile, "w");
268	} else {
269		out = BIO_new_fp(stdout, BIO_NOCLOSE);
270#ifdef OPENSSL_SYS_VMS
271		{
272		BIO *tmpbio = BIO_new(BIO_f_linebuffer());
273		out = BIO_push(tmpbio, out);
274		}
275#endif
276	}
277
278	if(!out) {
279		BIO_printf(bio_err, "Error opening output file %s\n",
280					outfile ? outfile : "(stdout)");
281		ERR_print_errors(bio_err);
282		goto end;
283	}
284
285	if(keyfile)
286		{
287		if (want_pub)
288			sigkey = load_pubkey(bio_err, keyfile, keyform, 0, NULL,
289				e, "key file");
290		else
291			sigkey = load_key(bio_err, keyfile, keyform, 0, NULL,
292				e, "key file");
293		if (!sigkey)
294			{
295			/* load_[pub]key() has already printed an appropriate
296			   message */
297			goto end;
298			}
299		}
300
301	if(sigfile && sigkey) {
302		BIO *sigbio;
303		sigbio = BIO_new_file(sigfile, "rb");
304		siglen = EVP_PKEY_size(sigkey);
305		sigbuf = OPENSSL_malloc(siglen);
306		if(!sigbio) {
307			BIO_printf(bio_err, "Error opening signature file %s\n",
308								sigfile);
309			ERR_print_errors(bio_err);
310			goto end;
311		}
312		siglen = BIO_read(sigbio, sigbuf, siglen);
313		BIO_free(sigbio);
314		if(siglen <= 0) {
315			BIO_printf(bio_err, "Error reading signature file %s\n",
316								sigfile);
317			ERR_print_errors(bio_err);
318			goto end;
319		}
320	}
321
322
323
324	/* we use md as a filter, reading from 'in' */
325	BIO_set_md(bmd,md);
326	inp=BIO_push(bmd,in);
327
328	if (argc == 0)
329		{
330		BIO_set_fp(in,stdin,BIO_NOCLOSE);
331		err=do_fp(out, buf,inp,separator, out_bin, sigkey, sigbuf,
332			  siglen,"","(stdin)");
333		}
334	else
335		{
336		name=OBJ_nid2sn(md->type);
337		for (i=0; i<argc; i++)
338			{
339			char *tmp,*tofree=NULL;
340			int r;
341
342			if (BIO_read_filename(in,argv[i]) <= 0)
343				{
344				perror(argv[i]);
345				err++;
346				continue;
347				}
348			if(!out_bin)
349				{
350				size_t len = strlen(name)+strlen(argv[i])+5;
351				tmp=tofree=OPENSSL_malloc(len);
352				BIO_snprintf(tmp,len,"%s(%s)= ",name,argv[i]);
353				}
354			else
355				tmp="";
356			r=do_fp(out,buf,inp,separator,out_bin,sigkey,sigbuf,
357				siglen,tmp,argv[i]);
358			if(r)
359			    err=r;
360			if(tofree)
361				OPENSSL_free(tofree);
362			(void)BIO_reset(bmd);
363			}
364		}
365end:
366	if (buf != NULL)
367		{
368		OPENSSL_cleanse(buf,BUFSIZE);
369		OPENSSL_free(buf);
370		}
371	if (in != NULL) BIO_free(in);
372	BIO_free_all(out);
373	EVP_PKEY_free(sigkey);
374	if(sigbuf) OPENSSL_free(sigbuf);
375	if (bmd != NULL) BIO_free(bmd);
376	apps_shutdown();
377	OPENSSL_EXIT(err);
378	}
379
380int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout,
381	  EVP_PKEY *key, unsigned char *sigin, int siglen, const char *title,
382	  const char *file)
383	{
384	int len;
385	int i;
386
387	for (;;)
388		{
389		i=BIO_read(bp,(char *)buf,BUFSIZE);
390		if(i < 0)
391			{
392			BIO_printf(bio_err, "Read Error in %s\n",file);
393			ERR_print_errors(bio_err);
394			return 1;
395			}
396		if (i == 0) break;
397		}
398	if(sigin)
399		{
400		EVP_MD_CTX *ctx;
401		BIO_get_md_ctx(bp, &ctx);
402		i = EVP_VerifyFinal(ctx, sigin, (unsigned int)siglen, key);
403		if(i > 0)
404			BIO_printf(out, "Verified OK\n");
405		else if(i == 0)
406			{
407			BIO_printf(out, "Verification Failure\n");
408			return 1;
409			}
410		else
411			{
412			BIO_printf(bio_err, "Error Verifying Data\n");
413			ERR_print_errors(bio_err);
414			return 1;
415			}
416		return 0;
417		}
418	if(key)
419		{
420		EVP_MD_CTX *ctx;
421		BIO_get_md_ctx(bp, &ctx);
422		if(!EVP_SignFinal(ctx, buf, (unsigned int *)&len, key))
423			{
424			BIO_printf(bio_err, "Error Signing Data\n");
425			ERR_print_errors(bio_err);
426			return 1;
427			}
428		}
429	else
430		len=BIO_gets(bp,(char *)buf,BUFSIZE);
431
432	if(binout) BIO_write(out, buf, len);
433	else
434		{
435		BIO_write(out,title,strlen(title));
436		for (i=0; i<len; i++)
437			{
438			if (sep && (i != 0))
439				BIO_printf(out, ":");
440			BIO_printf(out, "%02x",buf[i]);
441			}
442		BIO_printf(out, "\n");
443		}
444	return 0;
445	}
446
447