xref: /freebsd/crypto/openssl/apps/dgst.c (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
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 #include <openssl/hmac.h>
70 
71 #undef BUFSIZE
72 #define BUFSIZE 1024*8
73 
74 #undef PROG
75 #define PROG    dgst_main
76 
77 int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout,
78           EVP_PKEY *key, unsigned char *sigin, int siglen,
79           const char *sig_name, const char *md_name,
80           const char *file, BIO *bmd);
81 
82 static void list_md_fn(const EVP_MD *m,
83                        const char *from, const char *to, void *arg)
84 {
85     const char *mname;
86     /* Skip aliases */
87     if (!m)
88         return;
89     mname = OBJ_nid2ln(EVP_MD_type(m));
90     /* Skip shortnames */
91     if (strcmp(from, mname))
92         return;
93     /* Skip clones */
94     if (EVP_MD_flags(m) & EVP_MD_FLAG_PKEY_DIGEST)
95         return;
96     if (strchr(mname, ' '))
97         mname = EVP_MD_name(m);
98     BIO_printf(arg, "-%-14s to use the %s message digest algorithm\n",
99                mname, mname);
100 }
101 
102 int MAIN(int, char **);
103 
104 int MAIN(int argc, char **argv)
105 {
106     ENGINE *e = NULL;
107     unsigned char *buf = NULL;
108     int i, err = 1;
109     const EVP_MD *md = NULL, *m;
110     BIO *in = NULL, *inp;
111     BIO *bmd = NULL;
112     BIO *out = NULL;
113 #define PROG_NAME_SIZE  39
114     char pname[PROG_NAME_SIZE + 1];
115     int separator = 0;
116     int debug = 0;
117     int keyform = FORMAT_PEM;
118     const char *outfile = NULL, *keyfile = NULL;
119     const char *sigfile = NULL, *randfile = NULL;
120     int out_bin = -1, want_pub = 0, do_verify = 0;
121     EVP_PKEY *sigkey = NULL;
122     unsigned char *sigbuf = NULL;
123     int siglen = 0;
124     char *passargin = NULL, *passin = NULL;
125 #ifndef OPENSSL_NO_ENGINE
126     char *engine = NULL;
127 #endif
128     char *hmac_key = NULL;
129     char *mac_name = NULL;
130     int non_fips_allow = 0;
131     STACK_OF(OPENSSL_STRING) *sigopts = NULL, *macopts = NULL;
132 
133     apps_startup();
134 
135     if ((buf = (unsigned char *)OPENSSL_malloc(BUFSIZE)) == NULL) {
136         BIO_printf(bio_err, "out of memory\n");
137         goto end;
138     }
139     if (bio_err == NULL)
140         if ((bio_err = BIO_new(BIO_s_file())) != NULL)
141             BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
142 
143     if (!load_config(bio_err, NULL))
144         goto end;
145 
146     /* first check the program name */
147     program_name(argv[0], pname, sizeof pname);
148 
149     md = EVP_get_digestbyname(pname);
150 
151     argc--;
152     argv++;
153     while (argc > 0) {
154         if ((*argv)[0] != '-')
155             break;
156         if (strcmp(*argv, "-c") == 0)
157             separator = 1;
158         else if (strcmp(*argv, "-r") == 0)
159             separator = 2;
160         else if (strcmp(*argv, "-rand") == 0) {
161             if (--argc < 1)
162                 break;
163             randfile = *(++argv);
164         } else if (strcmp(*argv, "-out") == 0) {
165             if (--argc < 1)
166                 break;
167             outfile = *(++argv);
168         } else if (strcmp(*argv, "-sign") == 0) {
169             if (--argc < 1)
170                 break;
171             keyfile = *(++argv);
172         } else if (!strcmp(*argv, "-passin")) {
173             if (--argc < 1)
174                 break;
175             passargin = *++argv;
176         } else if (strcmp(*argv, "-verify") == 0) {
177             if (--argc < 1)
178                 break;
179             keyfile = *(++argv);
180             want_pub = 1;
181             do_verify = 1;
182         } else if (strcmp(*argv, "-prverify") == 0) {
183             if (--argc < 1)
184                 break;
185             keyfile = *(++argv);
186             do_verify = 1;
187         } else if (strcmp(*argv, "-signature") == 0) {
188             if (--argc < 1)
189                 break;
190             sigfile = *(++argv);
191         } else if (strcmp(*argv, "-keyform") == 0) {
192             if (--argc < 1)
193                 break;
194             keyform = str2fmt(*(++argv));
195         }
196 #ifndef OPENSSL_NO_ENGINE
197         else if (strcmp(*argv, "-engine") == 0) {
198             if (--argc < 1)
199                 break;
200             engine = *(++argv);
201             e = setup_engine(bio_err, engine, 0);
202         }
203 #endif
204         else if (strcmp(*argv, "-hex") == 0)
205             out_bin = 0;
206         else if (strcmp(*argv, "-binary") == 0)
207             out_bin = 1;
208         else if (strcmp(*argv, "-d") == 0)
209             debug = 1;
210         else if (!strcmp(*argv, "-fips-fingerprint"))
211             hmac_key = "etaonrishdlcupfm";
212         else if (strcmp(*argv, "-non-fips-allow") == 0)
213             non_fips_allow = 1;
214         else if (!strcmp(*argv, "-hmac")) {
215             if (--argc < 1)
216                 break;
217             hmac_key = *++argv;
218         } else if (!strcmp(*argv, "-mac")) {
219             if (--argc < 1)
220                 break;
221             mac_name = *++argv;
222         } else if (strcmp(*argv, "-sigopt") == 0) {
223             if (--argc < 1)
224                 break;
225             if (!sigopts)
226                 sigopts = sk_OPENSSL_STRING_new_null();
227             if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, *(++argv)))
228                 break;
229         } else if (strcmp(*argv, "-macopt") == 0) {
230             if (--argc < 1)
231                 break;
232             if (!macopts)
233                 macopts = sk_OPENSSL_STRING_new_null();
234             if (!macopts || !sk_OPENSSL_STRING_push(macopts, *(++argv)))
235                 break;
236         } else if ((m = EVP_get_digestbyname(&((*argv)[1]))) != NULL)
237             md = m;
238         else
239             break;
240         argc--;
241         argv++;
242     }
243 
244     if (do_verify && !sigfile) {
245         BIO_printf(bio_err,
246                    "No signature to verify: use the -signature option\n");
247         goto end;
248     }
249 
250     if ((argc > 0) && (argv[0][0] == '-')) { /* bad option */
251         BIO_printf(bio_err, "unknown option '%s'\n", *argv);
252         BIO_printf(bio_err, "options are\n");
253         BIO_printf(bio_err,
254                    "-c              to output the digest with separating colons\n");
255         BIO_printf(bio_err,
256                    "-r              to output the digest in coreutils format\n");
257         BIO_printf(bio_err, "-d              to output debug info\n");
258         BIO_printf(bio_err, "-hex            output as hex dump\n");
259         BIO_printf(bio_err, "-binary         output in binary form\n");
260         BIO_printf(bio_err, "-hmac arg       set the HMAC key to arg\n");
261         BIO_printf(bio_err, "-non-fips-allow allow use of non FIPS digest\n");
262         BIO_printf(bio_err,
263                    "-sign   file    sign digest using private key in file\n");
264         BIO_printf(bio_err,
265                    "-verify file    verify a signature using public key in file\n");
266         BIO_printf(bio_err,
267                    "-prverify file  verify a signature using private key in file\n");
268         BIO_printf(bio_err,
269                    "-keyform arg    key file format (PEM or ENGINE)\n");
270         BIO_printf(bio_err,
271                    "-out filename   output to filename rather than stdout\n");
272         BIO_printf(bio_err, "-signature file signature to verify\n");
273         BIO_printf(bio_err, "-sigopt nm:v    signature parameter\n");
274         BIO_printf(bio_err, "-hmac key       create hashed MAC with key\n");
275         BIO_printf(bio_err,
276                    "-mac algorithm  create MAC (not neccessarily HMAC)\n");
277         BIO_printf(bio_err,
278                    "-macopt nm:v    MAC algorithm parameters or key\n");
279 #ifndef OPENSSL_NO_ENGINE
280         BIO_printf(bio_err,
281                    "-engine e       use engine e, possibly a hardware device.\n");
282 #endif
283 
284         EVP_MD_do_all_sorted(list_md_fn, bio_err);
285         goto end;
286     }
287 
288     in = BIO_new(BIO_s_file());
289     bmd = BIO_new(BIO_f_md());
290     if ((in == NULL) || (bmd == NULL)) {
291         ERR_print_errors(bio_err);
292         goto end;
293     }
294 
295     if (debug) {
296         BIO_set_callback(in, BIO_debug_callback);
297         /* needed for windows 3.1 */
298         BIO_set_callback_arg(in, (char *)bio_err);
299     }
300 
301     if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
302         BIO_printf(bio_err, "Error getting password\n");
303         goto end;
304     }
305 
306     if (out_bin == -1) {
307         if (keyfile)
308             out_bin = 1;
309         else
310             out_bin = 0;
311     }
312 
313     if (randfile)
314         app_RAND_load_file(randfile, bio_err, 0);
315 
316     if (outfile) {
317         if (out_bin)
318             out = BIO_new_file(outfile, "wb");
319         else
320             out = BIO_new_file(outfile, "w");
321     } else {
322         out = BIO_new_fp(stdout, BIO_NOCLOSE);
323 #ifdef OPENSSL_SYS_VMS
324         {
325             BIO *tmpbio = BIO_new(BIO_f_linebuffer());
326             out = BIO_push(tmpbio, out);
327         }
328 #endif
329     }
330 
331     if (!out) {
332         BIO_printf(bio_err, "Error opening output file %s\n",
333                    outfile ? outfile : "(stdout)");
334         ERR_print_errors(bio_err);
335         goto end;
336     }
337     if ((! !mac_name + ! !keyfile + ! !hmac_key) > 1) {
338         BIO_printf(bio_err, "MAC and Signing key cannot both be specified\n");
339         goto end;
340     }
341 
342     if (keyfile) {
343         if (want_pub)
344             sigkey = load_pubkey(bio_err, keyfile, keyform, 0, NULL,
345                                  e, "key file");
346         else
347             sigkey = load_key(bio_err, keyfile, keyform, 0, passin,
348                               e, "key file");
349         if (!sigkey) {
350             /*
351              * load_[pub]key() has already printed an appropriate message
352              */
353             goto end;
354         }
355     }
356 
357     if (mac_name) {
358         EVP_PKEY_CTX *mac_ctx = NULL;
359         int r = 0;
360         if (!init_gen_str(bio_err, &mac_ctx, mac_name, e, 0))
361             goto mac_end;
362         if (macopts) {
363             char *macopt;
364             for (i = 0; i < sk_OPENSSL_STRING_num(macopts); i++) {
365                 macopt = sk_OPENSSL_STRING_value(macopts, i);
366                 if (pkey_ctrl_string(mac_ctx, macopt) <= 0) {
367                     BIO_printf(bio_err,
368                                "MAC parameter error \"%s\"\n", macopt);
369                     ERR_print_errors(bio_err);
370                     goto mac_end;
371                 }
372             }
373         }
374         if (EVP_PKEY_keygen(mac_ctx, &sigkey) <= 0) {
375             BIO_puts(bio_err, "Error generating key\n");
376             ERR_print_errors(bio_err);
377             goto mac_end;
378         }
379         r = 1;
380  mac_end:
381         if (mac_ctx)
382             EVP_PKEY_CTX_free(mac_ctx);
383         if (r == 0)
384             goto end;
385     }
386 
387     if (non_fips_allow) {
388         EVP_MD_CTX *md_ctx;
389         BIO_get_md_ctx(bmd, &md_ctx);
390         EVP_MD_CTX_set_flags(md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
391     }
392 
393     if (hmac_key) {
394         sigkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, e,
395                                       (unsigned char *)hmac_key, -1);
396         if (!sigkey)
397             goto end;
398     }
399 
400     if (sigkey) {
401         EVP_MD_CTX *mctx = NULL;
402         EVP_PKEY_CTX *pctx = NULL;
403         int r;
404         if (!BIO_get_md_ctx(bmd, &mctx)) {
405             BIO_printf(bio_err, "Error getting context\n");
406             ERR_print_errors(bio_err);
407             goto end;
408         }
409         if (do_verify)
410             r = EVP_DigestVerifyInit(mctx, &pctx, md, NULL, sigkey);
411         else
412             r = EVP_DigestSignInit(mctx, &pctx, md, NULL, sigkey);
413         if (!r) {
414             BIO_printf(bio_err, "Error setting context\n");
415             ERR_print_errors(bio_err);
416             goto end;
417         }
418         if (sigopts) {
419             char *sigopt;
420             for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) {
421                 sigopt = sk_OPENSSL_STRING_value(sigopts, i);
422                 if (pkey_ctrl_string(pctx, sigopt) <= 0) {
423                     BIO_printf(bio_err, "parameter error \"%s\"\n", sigopt);
424                     ERR_print_errors(bio_err);
425                     goto end;
426                 }
427             }
428         }
429     }
430     /* we use md as a filter, reading from 'in' */
431     else {
432         if (md == NULL)
433             md = EVP_md5();
434         if (!BIO_set_md(bmd, md)) {
435             BIO_printf(bio_err, "Error setting digest %s\n", pname);
436             ERR_print_errors(bio_err);
437             goto end;
438         }
439     }
440 
441     if (sigfile && sigkey) {
442         BIO *sigbio;
443         sigbio = BIO_new_file(sigfile, "rb");
444         siglen = EVP_PKEY_size(sigkey);
445         sigbuf = OPENSSL_malloc(siglen);
446         if (!sigbio) {
447             BIO_printf(bio_err, "Error opening signature file %s\n", sigfile);
448             ERR_print_errors(bio_err);
449             goto end;
450         }
451         if (!sigbuf) {
452             BIO_printf(bio_err, "Out of memory\n");
453             ERR_print_errors(bio_err);
454             goto end;
455         }
456         siglen = BIO_read(sigbio, sigbuf, siglen);
457         BIO_free(sigbio);
458         if (siglen <= 0) {
459             BIO_printf(bio_err, "Error reading signature file %s\n", sigfile);
460             ERR_print_errors(bio_err);
461             goto end;
462         }
463     }
464     inp = BIO_push(bmd, in);
465 
466     if (md == NULL) {
467         EVP_MD_CTX *tctx;
468         BIO_get_md_ctx(bmd, &tctx);
469         md = EVP_MD_CTX_md(tctx);
470     }
471 
472     if (argc == 0) {
473         BIO_set_fp(in, stdin, BIO_NOCLOSE);
474         err = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf,
475                     siglen, NULL, NULL, "stdin", bmd);
476     } else {
477         const char *md_name = NULL, *sig_name = NULL;
478         if (!out_bin) {
479             if (sigkey) {
480                 const EVP_PKEY_ASN1_METHOD *ameth;
481                 ameth = EVP_PKEY_get0_asn1(sigkey);
482                 if (ameth)
483                     EVP_PKEY_asn1_get0_info(NULL, NULL,
484                                             NULL, NULL, &sig_name, ameth);
485             }
486             md_name = EVP_MD_name(md);
487         }
488         err = 0;
489         for (i = 0; i < argc; i++) {
490             int r;
491             if (BIO_read_filename(in, argv[i]) <= 0) {
492                 perror(argv[i]);
493                 err++;
494                 continue;
495             } else
496                 r = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf,
497                           siglen, sig_name, md_name, argv[i], bmd);
498             if (r)
499                 err = r;
500             (void)BIO_reset(bmd);
501         }
502     }
503  end:
504     if (buf != NULL) {
505         OPENSSL_cleanse(buf, BUFSIZE);
506         OPENSSL_free(buf);
507     }
508     if (in != NULL)
509         BIO_free(in);
510     if (passin)
511         OPENSSL_free(passin);
512     BIO_free_all(out);
513     EVP_PKEY_free(sigkey);
514     if (sigopts)
515         sk_OPENSSL_STRING_free(sigopts);
516     if (macopts)
517         sk_OPENSSL_STRING_free(macopts);
518     if (sigbuf)
519         OPENSSL_free(sigbuf);
520     if (bmd != NULL)
521         BIO_free(bmd);
522     apps_shutdown();
523     OPENSSL_EXIT(err);
524 }
525 
526 int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout,
527           EVP_PKEY *key, unsigned char *sigin, int siglen,
528           const char *sig_name, const char *md_name,
529           const char *file, BIO *bmd)
530 {
531     size_t len;
532     int i;
533 
534     for (;;) {
535         i = BIO_read(bp, (char *)buf, BUFSIZE);
536         if (i < 0) {
537             BIO_printf(bio_err, "Read Error in %s\n", file);
538             ERR_print_errors(bio_err);
539             return 1;
540         }
541         if (i == 0)
542             break;
543     }
544     if (sigin) {
545         EVP_MD_CTX *ctx;
546         BIO_get_md_ctx(bp, &ctx);
547         i = EVP_DigestVerifyFinal(ctx, sigin, (unsigned int)siglen);
548         if (i > 0)
549             BIO_printf(out, "Verified OK\n");
550         else if (i == 0) {
551             BIO_printf(out, "Verification Failure\n");
552             return 1;
553         } else {
554             BIO_printf(bio_err, "Error Verifying Data\n");
555             ERR_print_errors(bio_err);
556             return 1;
557         }
558         return 0;
559     }
560     if (key) {
561         EVP_MD_CTX *ctx;
562         BIO_get_md_ctx(bp, &ctx);
563         len = BUFSIZE;
564         if (!EVP_DigestSignFinal(ctx, buf, &len)) {
565             BIO_printf(bio_err, "Error Signing Data\n");
566             ERR_print_errors(bio_err);
567             return 1;
568         }
569     } else {
570         len = BIO_gets(bp, (char *)buf, BUFSIZE);
571         if ((int)len < 0) {
572             ERR_print_errors(bio_err);
573             return 1;
574         }
575     }
576 
577     if (binout)
578         BIO_write(out, buf, len);
579     else if (sep == 2) {
580         for (i = 0; i < (int)len; i++)
581             BIO_printf(out, "%02x", buf[i]);
582         BIO_printf(out, " *%s\n", file);
583     } else {
584         if (sig_name)
585             BIO_printf(out, "%s-%s(%s)= ", sig_name, md_name, file);
586         else if (md_name)
587             BIO_printf(out, "%s(%s)= ", md_name, file);
588         else
589             BIO_printf(out, "(%s)= ", file);
590         for (i = 0; i < (int)len; i++) {
591             if (sep && (i != 0))
592                 BIO_printf(out, ":");
593             BIO_printf(out, "%02x", buf[i]);
594         }
595         BIO_printf(out, "\n");
596     }
597     return 0;
598 }
599