7fa535197ef77a73836b785b3147f890ad6543ac
[openssl.git] / apps / dgst.c
1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@cryptsoft.com).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young (eay@cryptsoft.com)"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.]
56  */
57
58 #include <stdio.h>
59 #include <string.h>
60 #include <stdlib.h>
61 #include "apps.h"
62 #include <openssl/bio.h>
63 #include <openssl/err.h>
64 #include <openssl/evp.h>
65 #include <openssl/objects.h>
66 #include <openssl/x509.h>
67 #include <openssl/pem.h>
68 #include <openssl/hmac.h>
69
70 #undef BUFSIZE
71 #define BUFSIZE 1024*8
72
73 int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout,
74           EVP_PKEY *key, unsigned char *sigin, int siglen,
75           const char *sig_name, const char *md_name,
76           const char *file, BIO *bmd);
77
78 typedef enum OPTION_choice {
79     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
80     OPT_C, OPT_R, OPT_RAND, OPT_OUT, OPT_SIGN, OPT_PASSIN, OPT_VERIFY,
81     OPT_PRVERIFY, OPT_SIGNATURE, OPT_KEYFORM, OPT_ENGINE, OPT_ENGINE_IMPL,
82     OPT_HEX, OPT_BINARY, OPT_DEBUG, OPT_FIPS_FINGERPRINT,
83     OPT_HMAC, OPT_MAC, OPT_SIGOPT, OPT_MACOPT,
84     OPT_DIGEST
85 } OPTION_CHOICE;
86
87 OPTIONS dgst_options[] = {
88     {OPT_HELP_STR, 1, '-', "Usage: %s [options] [file...]\n"},
89     {OPT_HELP_STR, 1, '-',
90         "  file... files to digest (default is stdin)\n"},
91     {"help", OPT_HELP, '-', "Display this summary"},
92     {"c", OPT_C, '-', "Print the digest with separating colons"},
93     {"r", OPT_R, '-', "Print the digest in coreutils format"},
94     {"rand", OPT_RAND, 's',
95      "Use file(s) containing random data to seed RNG or an EGD sock"},
96     {"out", OPT_OUT, '>', "Output to filename rather than stdout"},
97     {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
98     {"sign", OPT_SIGN, '<', "Sign digest using private key in file"},
99     {"verify", OPT_VERIFY, '<',
100      "Verify a signature using public key in file"},
101     {"prverify", OPT_PRVERIFY, '<',
102      "Verify a signature using private key in file"},
103     {"signature", OPT_SIGNATURE, '<', "File with signature to verify"},
104     {"keyform", OPT_KEYFORM, 'f', "Key file format (PEM or ENGINE)"},
105     {"hex", OPT_HEX, '-', "Print as hex dump"},
106     {"binary", OPT_BINARY, '-', "Print in binary form"},
107     {"d", OPT_DEBUG, '-', "Print debug info"},
108     {"debug", OPT_DEBUG, '-', "Print debug info"},
109     {"fips-fingerprint", OPT_FIPS_FINGERPRINT, '-',
110      "Compute HMAC with the key used in OpenSSL-FIPS fingerprint"},
111     {"hmac", OPT_HMAC, 's', "Create hashed MAC with key"},
112     {"mac", OPT_MAC, 's', "Create MAC (not necessarily HMAC)"},
113     {"sigopt", OPT_SIGOPT, 's', "Signature parameter in n:v form"},
114     {"macopt", OPT_MACOPT, 's', "MAC algorithm parameters in n:v form or key"},
115     {"", OPT_DIGEST, '-', "Any supported digest"},
116 #ifndef OPENSSL_NO_ENGINE
117     {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"},
118     {"engine_impl", OPT_ENGINE_IMPL, '-',
119      "Also use engine given by -engine for digest operations"},
120 #endif
121     {NULL}
122 };
123
124 int dgst_main(int argc, char **argv)
125 {
126     BIO *in = NULL, *inp, *bmd = NULL, *out = NULL;
127     ENGINE *e = NULL, *impl = NULL;
128     EVP_PKEY *sigkey = NULL;
129     STACK_OF(OPENSSL_STRING) *sigopts = NULL, *macopts = NULL;
130     char *hmac_key = NULL;
131     char *mac_name = NULL;
132     char *passinarg = NULL, *passin = NULL;
133     const EVP_MD *md = NULL, *m;
134     const char *outfile = NULL, *keyfile = NULL, *prog = NULL;
135     const char *sigfile = NULL, *randfile = NULL;
136     OPTION_CHOICE o;
137     int separator = 0, debug = 0, keyform = FORMAT_PEM, siglen = 0;
138     int i, ret = 1, out_bin = -1, want_pub = 0, do_verify = 0;
139     unsigned char *buf = NULL, *sigbuf = NULL;
140     int engine_impl = 0;
141
142     prog = opt_progname(argv[0]);
143     buf = app_malloc(BUFSIZE, "I/O buffer");
144     md = EVP_get_digestbyname(prog);
145
146     prog = opt_init(argc, argv, dgst_options);
147     while ((o = opt_next()) != OPT_EOF) {
148         switch (o) {
149         case OPT_EOF:
150         case OPT_ERR:
151  opthelp:
152             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
153             goto end;
154         case OPT_HELP:
155             opt_help(dgst_options);
156             ret = 0;
157             goto end;
158         case OPT_C:
159             separator = 1;
160             break;
161         case OPT_R:
162             separator = 2;
163             break;
164         case OPT_RAND:
165             randfile = opt_arg();
166             break;
167         case OPT_OUT:
168             outfile = opt_arg();
169             break;
170         case OPT_SIGN:
171             keyfile = opt_arg();
172             break;
173         case OPT_PASSIN:
174             passinarg = opt_arg();
175             break;
176         case OPT_VERIFY:
177             keyfile = opt_arg();
178             want_pub = do_verify = 1;
179             break;
180         case OPT_PRVERIFY:
181             keyfile = opt_arg();
182             do_verify = 1;
183             break;
184         case OPT_SIGNATURE:
185             sigfile = opt_arg();
186             break;
187         case OPT_KEYFORM:
188             if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform))
189                 goto opthelp;
190             break;
191         case OPT_ENGINE:
192             e = setup_engine(opt_arg(), 0);
193             break;
194         case OPT_ENGINE_IMPL:
195             engine_impl = 1;
196             break;
197         case OPT_HEX:
198             out_bin = 0;
199             break;
200         case OPT_BINARY:
201             out_bin = 1;
202             break;
203         case OPT_DEBUG:
204             debug = 1;
205             break;
206         case OPT_FIPS_FINGERPRINT:
207             hmac_key = "etaonrishdlcupfm";
208             break;
209         case OPT_HMAC:
210             hmac_key = opt_arg();
211             break;
212         case OPT_MAC:
213             mac_name = opt_arg();
214             break;
215         case OPT_SIGOPT:
216             if (!sigopts)
217                 sigopts = sk_OPENSSL_STRING_new_null();
218             if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, opt_arg()))
219                 goto opthelp;
220             break;
221         case OPT_MACOPT:
222             if (!macopts)
223                 macopts = sk_OPENSSL_STRING_new_null();
224             if (!macopts || !sk_OPENSSL_STRING_push(macopts, opt_arg()))
225                 goto opthelp;
226             break;
227         case OPT_DIGEST:
228             if (!opt_md(opt_unknown(), &m))
229                 goto opthelp;
230             md = m;
231             break;
232         }
233     }
234     argc = opt_num_rest();
235     argv = opt_rest();
236
237     if (do_verify && !sigfile) {
238         BIO_printf(bio_err,
239                    "No signature to verify: use the -signature option\n");
240         goto end;
241     }
242     if (engine_impl)
243         impl = e;
244
245     in = BIO_new(BIO_s_file());
246     bmd = BIO_new(BIO_f_md());
247     if ((in == NULL) || (bmd == NULL)) {
248         ERR_print_errors(bio_err);
249         goto end;
250     }
251
252     if (debug) {
253         BIO_set_callback(in, BIO_debug_callback);
254         /* needed for windows 3.1 */
255         BIO_set_callback_arg(in, (char *)bio_err);
256     }
257
258     if (!app_passwd(passinarg, NULL, &passin, NULL)) {
259         BIO_printf(bio_err, "Error getting password\n");
260         goto end;
261     }
262
263     if (out_bin == -1) {
264         if (keyfile)
265             out_bin = 1;
266         else
267             out_bin = 0;
268     }
269
270     if (randfile)
271         app_RAND_load_file(randfile, 0);
272
273     out = bio_open_default(outfile, 'w', out_bin ? FORMAT_BINARY : FORMAT_TEXT);
274     if (out == NULL)
275         goto end;
276
277     if ((! !mac_name + ! !keyfile + ! !hmac_key) > 1) {
278         BIO_printf(bio_err, "MAC and Signing key cannot both be specified\n");
279         goto end;
280     }
281
282     if (keyfile) {
283         if (want_pub)
284             sigkey = load_pubkey(keyfile, keyform, 0, NULL, e, "key file");
285         else
286             sigkey = load_key(keyfile, keyform, 0, passin, e, "key file");
287         if (!sigkey) {
288             /*
289              * load_[pub]key() has already printed an appropriate message
290              */
291             goto end;
292         }
293     }
294
295     if (mac_name) {
296         EVP_PKEY_CTX *mac_ctx = NULL;
297         int r = 0;
298         if (!init_gen_str(&mac_ctx, mac_name, impl, 0))
299             goto mac_end;
300         if (macopts) {
301             char *macopt;
302             for (i = 0; i < sk_OPENSSL_STRING_num(macopts); i++) {
303                 macopt = sk_OPENSSL_STRING_value(macopts, i);
304                 if (pkey_ctrl_string(mac_ctx, macopt) <= 0) {
305                     BIO_printf(bio_err,
306                                "MAC parameter error \"%s\"\n", macopt);
307                     ERR_print_errors(bio_err);
308                     goto mac_end;
309                 }
310             }
311         }
312         if (EVP_PKEY_keygen(mac_ctx, &sigkey) <= 0) {
313             BIO_puts(bio_err, "Error generating key\n");
314             ERR_print_errors(bio_err);
315             goto mac_end;
316         }
317         r = 1;
318  mac_end:
319         EVP_PKEY_CTX_free(mac_ctx);
320         if (r == 0)
321             goto end;
322     }
323
324     if (hmac_key) {
325         sigkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, impl,
326                                       (unsigned char *)hmac_key, -1);
327         if (!sigkey)
328             goto end;
329     }
330
331     if (sigkey) {
332         EVP_MD_CTX *mctx = NULL;
333         EVP_PKEY_CTX *pctx = NULL;
334         int r;
335         if (!BIO_get_md_ctx(bmd, &mctx)) {
336             BIO_printf(bio_err, "Error getting context\n");
337             ERR_print_errors(bio_err);
338             goto end;
339         }
340         if (do_verify)
341             r = EVP_DigestVerifyInit(mctx, &pctx, md, impl, sigkey);
342         else
343             r = EVP_DigestSignInit(mctx, &pctx, md, impl, sigkey);
344         if (!r) {
345             BIO_printf(bio_err, "Error setting context\n");
346             ERR_print_errors(bio_err);
347             goto end;
348         }
349         if (sigopts) {
350             char *sigopt;
351             for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) {
352                 sigopt = sk_OPENSSL_STRING_value(sigopts, i);
353                 if (pkey_ctrl_string(pctx, sigopt) <= 0) {
354                     BIO_printf(bio_err, "parameter error \"%s\"\n", sigopt);
355                     ERR_print_errors(bio_err);
356                     goto end;
357                 }
358             }
359         }
360     }
361     /* we use md as a filter, reading from 'in' */
362     else {
363         EVP_MD_CTX *mctx = NULL;
364         if (!BIO_get_md_ctx(bmd, &mctx)) {
365             BIO_printf(bio_err, "Error getting context\n");
366             ERR_print_errors(bio_err);
367             goto end;
368         }
369         if (md == NULL)
370             md = EVP_sha256();
371         if (!EVP_DigestInit_ex(mctx, md, impl)) {
372             BIO_printf(bio_err, "Error setting digest\n");
373             ERR_print_errors(bio_err);
374             goto end;
375         }
376     }
377
378     if (sigfile && sigkey) {
379         BIO *sigbio = BIO_new_file(sigfile, "rb");
380         if (!sigbio) {
381             BIO_printf(bio_err, "Error opening signature file %s\n", sigfile);
382             ERR_print_errors(bio_err);
383             goto end;
384         }
385         siglen = EVP_PKEY_size(sigkey);
386         sigbuf = app_malloc(siglen, "signature buffer");
387         siglen = BIO_read(sigbio, sigbuf, siglen);
388         BIO_free(sigbio);
389         if (siglen <= 0) {
390             BIO_printf(bio_err, "Error reading signature file %s\n", sigfile);
391             ERR_print_errors(bio_err);
392             goto end;
393         }
394     }
395     inp = BIO_push(bmd, in);
396
397     if (md == NULL) {
398         EVP_MD_CTX *tctx;
399         BIO_get_md_ctx(bmd, &tctx);
400         md = EVP_MD_CTX_md(tctx);
401     }
402
403     if (argc == 0) {
404         BIO_set_fp(in, stdin, BIO_NOCLOSE);
405         ret = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf,
406                     siglen, NULL, NULL, "stdin", bmd);
407     } else {
408         const char *md_name = NULL, *sig_name = NULL;
409         if (!out_bin) {
410             if (sigkey) {
411                 const EVP_PKEY_ASN1_METHOD *ameth;
412                 ameth = EVP_PKEY_get0_asn1(sigkey);
413                 if (ameth)
414                     EVP_PKEY_asn1_get0_info(NULL, NULL,
415                                             NULL, NULL, &sig_name, ameth);
416             }
417             if (md)
418                 md_name = EVP_MD_name(md);
419         }
420         ret = 0;
421         for (i = 0; i < argc; i++) {
422             int r;
423             if (BIO_read_filename(in, argv[i]) <= 0) {
424                 perror(argv[i]);
425                 ret++;
426                 continue;
427             } else
428                 r = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf,
429                           siglen, sig_name, md_name, argv[i], bmd);
430             if (r)
431                 ret = r;
432             (void)BIO_reset(bmd);
433         }
434     }
435  end:
436     OPENSSL_clear_free(buf, BUFSIZE);
437     BIO_free(in);
438     OPENSSL_free(passin);
439     BIO_free_all(out);
440     EVP_PKEY_free(sigkey);
441     sk_OPENSSL_STRING_free(sigopts);
442     sk_OPENSSL_STRING_free(macopts);
443     OPENSSL_free(sigbuf);
444     BIO_free(bmd);
445     return (ret);
446 }
447
448 int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout,
449           EVP_PKEY *key, unsigned char *sigin, int siglen,
450           const char *sig_name, const char *md_name,
451           const char *file, BIO *bmd)
452 {
453     size_t len;
454     int i;
455
456     for (;;) {
457         i = BIO_read(bp, (char *)buf, BUFSIZE);
458         if (i < 0) {
459             BIO_printf(bio_err, "Read Error in %s\n", file);
460             ERR_print_errors(bio_err);
461             return 1;
462         }
463         if (i == 0)
464             break;
465     }
466     if (sigin) {
467         EVP_MD_CTX *ctx;
468         BIO_get_md_ctx(bp, &ctx);
469         i = EVP_DigestVerifyFinal(ctx, sigin, (unsigned int)siglen);
470         if (i > 0)
471             BIO_printf(out, "Verified OK\n");
472         else if (i == 0) {
473             BIO_printf(out, "Verification Failure\n");
474             return 1;
475         } else {
476             BIO_printf(bio_err, "Error Verifying Data\n");
477             ERR_print_errors(bio_err);
478             return 1;
479         }
480         return 0;
481     }
482     if (key) {
483         EVP_MD_CTX *ctx;
484         BIO_get_md_ctx(bp, &ctx);
485         len = BUFSIZE;
486         if (!EVP_DigestSignFinal(ctx, buf, &len)) {
487             BIO_printf(bio_err, "Error Signing Data\n");
488             ERR_print_errors(bio_err);
489             return 1;
490         }
491     } else {
492         len = BIO_gets(bp, (char *)buf, BUFSIZE);
493         if ((int)len < 0) {
494             ERR_print_errors(bio_err);
495             return 1;
496         }
497     }
498
499     if (binout)
500         BIO_write(out, buf, len);
501     else if (sep == 2) {
502         for (i = 0; i < (int)len; i++)
503             BIO_printf(out, "%02x", buf[i]);
504         BIO_printf(out, " *%s\n", file);
505     } else {
506         if (sig_name) {
507             BIO_puts(out, sig_name);
508             if (md_name)
509                 BIO_printf(out, "-%s", md_name);
510             BIO_printf(out, "(%s)= ", file);
511         } else if (md_name)
512             BIO_printf(out, "%s(%s)= ", md_name, file);
513         else
514             BIO_printf(out, "(%s)= ", file);
515         for (i = 0; i < (int)len; i++) {
516             if (sep && (i != 0))
517                 BIO_printf(out, ":");
518             BIO_printf(out, "%02x", buf[i]);
519         }
520         BIO_printf(out, "\n");
521     }
522     return 0;
523 }