nrelease - fix/improve livecd
[dragonfly.git] / crypto / libressl / apps / openssl / dgst.c
1 /* $OpenBSD: dgst.c,v 1.19 2022/01/14 09:28:07 tb Exp $ */
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 <stdlib.h>
61 #include <string.h>
62
63 #include "apps.h"
64
65 #include <openssl/bio.h>
66 #include <openssl/err.h>
67 #include <openssl/evp.h>
68 #include <openssl/hmac.h>
69 #include <openssl/objects.h>
70 #include <openssl/pem.h>
71 #include <openssl/x509.h>
72
73 #define BUFSIZE 1024*8
74
75 int
76 do_fp(BIO * out, unsigned char *buf, BIO * bp, int sep, int binout,
77     EVP_PKEY * key, unsigned char *sigin, int siglen,
78     const char *sig_name, const char *md_name,
79     const char *file, BIO * bmd);
80
81 static struct {
82         int argsused;
83         int debug;
84         int do_verify;
85         char *hmac_key;
86         char *keyfile;
87         int keyform;
88         const EVP_MD *m;
89         char *mac_name;
90         STACK_OF(OPENSSL_STRING) *macopts;
91         const EVP_MD *md;
92         int out_bin;
93         char *outfile;
94         char *passargin;
95         int separator;
96         char *sigfile;
97         STACK_OF(OPENSSL_STRING) *sigopts;
98         int want_pub;
99 } dgst_config;
100
101 static int
102 dgst_opt_macopt(char *arg)
103 {
104         if (arg == NULL)
105                 return (1);
106
107         if (dgst_config.macopts == NULL &&
108             (dgst_config.macopts = sk_OPENSSL_STRING_new_null()) == NULL)
109                 return (1);
110
111         if (!sk_OPENSSL_STRING_push(dgst_config.macopts, arg))
112                 return (1);
113
114         return (0);
115 }
116
117 static int
118 dgst_opt_md(int argc, char **argv, int *argsused)
119 {
120         char *name = argv[0];
121
122         if (*name++ != '-')
123                 return (1);
124
125         if ((dgst_config.m = EVP_get_digestbyname(name)) == NULL)
126                 return (1);
127
128         dgst_config.md = dgst_config.m;
129
130         *argsused = 1;
131         return (0);
132 }
133
134 static int
135 dgst_opt_prverify(char *arg)
136 {
137         if (arg == NULL)
138                 return (1);
139
140         dgst_config.keyfile = arg;
141         dgst_config.do_verify = 1;
142         return (0);
143 }
144
145 static int
146 dgst_opt_sigopt(char *arg)
147 {
148         if (arg == NULL)
149                 return (1);
150
151         if (dgst_config.sigopts == NULL &&
152             (dgst_config.sigopts = sk_OPENSSL_STRING_new_null()) == NULL)
153                 return (1);
154
155         if (!sk_OPENSSL_STRING_push(dgst_config.sigopts, arg))
156                 return (1);
157
158         return (0);
159 }
160
161 static int
162 dgst_opt_verify(char *arg)
163 {
164         if (arg == NULL)
165                 return (1);
166
167         dgst_config.keyfile = arg;
168         dgst_config.want_pub = 1;
169         dgst_config.do_verify = 1;
170         return (0);
171 }
172
173 static const struct option dgst_options[] = {
174         {
175                 .name = "binary",
176                 .desc = "Output the digest or signature in binary form",
177                 .type = OPTION_VALUE,
178                 .opt.value = &dgst_config.out_bin,
179                 .value = 1,
180         },
181         {
182                 .name = "c",
183                 .desc = "Print the digest in two-digit groups separated by colons",
184                 .type = OPTION_VALUE,
185                 .opt.value = &dgst_config.separator,
186                 .value = 1,
187         },
188         {
189                 .name = "d",
190                 .desc = "Print BIO debugging information",
191                 .type = OPTION_FLAG,
192                 .opt.flag = &dgst_config.debug,
193         },
194         {
195                 .name = "hex",
196                 .desc = "Output as hex dump",
197                 .type = OPTION_VALUE,
198                 .opt.value = &dgst_config.out_bin,
199                 .value = 0,
200         },
201         {
202                 .name = "hmac",
203                 .argname = "key",
204                 .desc = "Create hashed MAC with key",
205                 .type = OPTION_ARG,
206                 .opt.arg = &dgst_config.hmac_key,
207         },
208         {
209                 .name = "keyform",
210                 .argname = "format",
211                 .desc = "Key file format (PEM)",
212                 .type = OPTION_ARG_FORMAT,
213                 .opt.value = &dgst_config.keyform,
214         },
215         {
216                 .name = "mac",
217                 .argname = "algorithm",
218                 .desc = "Create MAC (not necessarily HMAC)",
219                 .type = OPTION_ARG,
220                 .opt.arg = &dgst_config.mac_name,
221         },
222         {
223                 .name = "macopt",
224                 .argname = "nm:v",
225                 .desc = "MAC algorithm parameters or key",
226                 .type = OPTION_ARG_FUNC,
227                 .opt.argfunc = dgst_opt_macopt,
228         },
229         {
230                 .name = "out",
231                 .argname = "file",
232                 .desc = "Output to file rather than stdout",
233                 .type = OPTION_ARG,
234                 .opt.arg = &dgst_config.outfile,
235         },
236         {
237                 .name = "passin",
238                 .argname = "arg",
239                 .desc = "Input file passphrase source",
240                 .type = OPTION_ARG,
241                 .opt.arg = &dgst_config.passargin,
242         },
243         {
244                 .name = "prverify",
245                 .argname = "file",
246                 .desc = "Verify a signature using private key in file",
247                 .type = OPTION_ARG_FUNC,
248                 .opt.argfunc = dgst_opt_prverify,
249         },
250         {
251                 .name = "r",
252                 .desc = "Output the digest in coreutils format",
253                 .type = OPTION_VALUE,
254                 .opt.value = &dgst_config.separator,
255                 .value = 2,
256         },
257         {
258                 .name = "sign",
259                 .argname = "file",
260                 .desc = "Sign digest using private key in file",
261                 .type = OPTION_ARG,
262                 .opt.arg = &dgst_config.keyfile,
263         },
264         {
265                 .name = "signature",
266                 .argname = "file",
267                 .desc = "Signature to verify",
268                 .type = OPTION_ARG,
269                 .opt.arg = &dgst_config.sigfile,
270         },
271         {
272                 .name = "sigopt",
273                 .argname = "nm:v",
274                 .desc = "Signature parameter",
275                 .type = OPTION_ARG_FUNC,
276                 .opt.argfunc = dgst_opt_sigopt,
277         },
278         {
279                 .name = "verify",
280                 .argname = "file",
281                 .desc = "Verify a signature using public key in file",
282                 .type = OPTION_ARG_FUNC,
283                 .opt.argfunc = dgst_opt_verify,
284         },
285         {
286                 .name = NULL,
287                 .desc = "",
288                 .type = OPTION_ARGV_FUNC,
289                 .opt.argvfunc = dgst_opt_md,
290         },
291         { NULL },
292 };
293
294 static void
295 list_md_fn(const EVP_MD * m, const char *from, const char *to, void *arg)
296 {
297         const char *mname;
298         /* Skip aliases */
299         if (!m)
300                 return;
301         mname = OBJ_nid2ln(EVP_MD_type(m));
302         /* Skip shortnames */
303         if (strcmp(from, mname))
304                 return;
305         if (strchr(mname, ' '))
306                 mname = EVP_MD_name(m);
307         BIO_printf(arg, " -%-17s To use the %s message digest algorithm\n",
308             mname, mname);
309 }
310
311 static void
312 dgst_usage(void)
313 {
314         fprintf(stderr, "usage: dgst [-cdr] [-binary] [-digest] [-hex]");
315         fprintf(stderr, " [-hmac key] [-keyform fmt]\n");
316         fprintf(stderr, "    [-mac algorithm] [-macopt nm:v] [-out file]");
317         fprintf(stderr, " [-passin arg]\n");
318         fprintf(stderr, "    [-prverify file] [-sign file]");
319         fprintf(stderr, " [-signature file]\n");
320         fprintf(stderr, "    [-sigopt nm:v] [-verify file] [file ...]\n\n");
321         options_usage(dgst_options);
322         EVP_MD_do_all_sorted(list_md_fn, bio_err);
323         fprintf(stderr, "\n");
324 }
325
326 int
327 dgst_main(int argc, char **argv)
328 {
329         unsigned char *buf = NULL;
330         int i, err = 1;
331         BIO *in = NULL, *inp;
332         BIO *bmd = NULL;
333         BIO *out = NULL;
334 #define PROG_NAME_SIZE  39
335         char pname[PROG_NAME_SIZE + 1];
336         EVP_PKEY *sigkey = NULL;
337         unsigned char *sigbuf = NULL;
338         int siglen = 0;
339         char *passin = NULL;
340
341         if (single_execution) {
342                 if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
343                         perror("pledge");
344                         exit(1);
345                 }
346         }
347
348         if ((buf = malloc(BUFSIZE)) == NULL) {
349                 BIO_printf(bio_err, "out of memory\n");
350                 goto end;
351         }
352
353         memset(&dgst_config, 0, sizeof(dgst_config));
354         dgst_config.keyform = FORMAT_PEM;
355         dgst_config.out_bin = -1;
356
357         /* first check the program name */
358         program_name(argv[0], pname, sizeof pname);
359
360         dgst_config.md = EVP_get_digestbyname(pname);
361
362         if (options_parse(argc, argv, dgst_options, NULL,
363             &dgst_config.argsused) != 0) {
364                 dgst_usage();
365                 goto end;
366         }
367         argc -= dgst_config.argsused;
368         argv += dgst_config.argsused;
369
370         if (dgst_config.do_verify && !dgst_config.sigfile) {
371                 BIO_printf(bio_err,
372                     "No signature to verify: use the -signature option\n");
373                 goto end;
374         }
375
376         in = BIO_new(BIO_s_file());
377         bmd = BIO_new(BIO_f_md());
378         if (in == NULL || bmd == NULL) {
379                 ERR_print_errors(bio_err);
380                 goto end;
381         }
382
383         if (dgst_config.debug) {
384                 BIO_set_callback(in, BIO_debug_callback);
385                 /* needed for windows 3.1 */
386                 BIO_set_callback_arg(in, (char *) bio_err);
387         }
388         if (!app_passwd(bio_err, dgst_config.passargin, NULL, &passin, NULL)) {
389                 BIO_printf(bio_err, "Error getting password\n");
390                 goto end;
391         }
392         if (dgst_config.out_bin == -1) {
393                 if (dgst_config.keyfile)
394                         dgst_config.out_bin = 1;
395                 else
396                         dgst_config.out_bin = 0;
397         }
398
399         if (dgst_config.outfile) {
400                 if (dgst_config.out_bin)
401                         out = BIO_new_file(dgst_config.outfile, "wb");
402                 else
403                         out = BIO_new_file(dgst_config.outfile, "w");
404         } else {
405                 out = BIO_new_fp(stdout, BIO_NOCLOSE);
406         }
407
408         if (!out) {
409                 BIO_printf(bio_err, "Error opening output file %s\n",
410                     dgst_config.outfile ? dgst_config.outfile : "(stdout)");
411                 ERR_print_errors(bio_err);
412                 goto end;
413         }
414         if ((!!dgst_config.mac_name + !!dgst_config.keyfile +
415             !!dgst_config.hmac_key) > 1) {
416                 BIO_printf(bio_err,
417                     "MAC and Signing key cannot both be specified\n");
418                 goto end;
419         }
420         if (dgst_config.keyfile) {
421                 if (dgst_config.want_pub)
422                         sigkey = load_pubkey(bio_err, dgst_config.keyfile,
423                             dgst_config.keyform, 0, NULL, "key file");
424                 else
425                         sigkey = load_key(bio_err, dgst_config.keyfile,
426                             dgst_config.keyform, 0, passin, "key file");
427                 if (!sigkey) {
428                         /*
429                          * load_[pub]key() has already printed an appropriate
430                          * message
431                          */
432                         goto end;
433                 }
434         }
435         if (dgst_config.mac_name) {
436                 EVP_PKEY_CTX *mac_ctx = NULL;
437                 int r = 0;
438                 if (!init_gen_str(bio_err, &mac_ctx, dgst_config.mac_name, 0))
439                         goto mac_end;
440                 if (dgst_config.macopts) {
441                         char *macopt;
442                         for (i = 0; i < sk_OPENSSL_STRING_num(
443                             dgst_config.macopts); i++) {
444                                 macopt = sk_OPENSSL_STRING_value(
445                                     dgst_config.macopts, i);
446                                 if (pkey_ctrl_string(mac_ctx, macopt) <= 0) {
447                                         BIO_printf(bio_err,
448                                             "MAC parameter error \"%s\"\n",
449                                             macopt);
450                                         ERR_print_errors(bio_err);
451                                         goto mac_end;
452                                 }
453                         }
454                 }
455                 if (EVP_PKEY_keygen(mac_ctx, &sigkey) <= 0) {
456                         BIO_puts(bio_err, "Error generating key\n");
457                         ERR_print_errors(bio_err);
458                         goto mac_end;
459                 }
460                 r = 1;
461  mac_end:
462                 EVP_PKEY_CTX_free(mac_ctx);
463                 if (r == 0)
464                         goto end;
465         }
466         if (dgst_config.hmac_key) {
467                 sigkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL,
468                     (unsigned char *) dgst_config.hmac_key, -1);
469                 if (!sigkey)
470                         goto end;
471         }
472         if (sigkey) {
473                 EVP_MD_CTX *mctx = NULL;
474                 EVP_PKEY_CTX *pctx = NULL;
475                 int r;
476                 if (!BIO_get_md_ctx(bmd, &mctx)) {
477                         BIO_printf(bio_err, "Error getting context\n");
478                         ERR_print_errors(bio_err);
479                         goto end;
480                 }
481                 if (dgst_config.do_verify)
482                         r = EVP_DigestVerifyInit(mctx, &pctx, dgst_config.md,
483                             NULL, sigkey);
484                 else
485                         r = EVP_DigestSignInit(mctx, &pctx, dgst_config.md,
486                             NULL, sigkey);
487                 if (!r) {
488                         BIO_printf(bio_err, "Error setting context\n");
489                         ERR_print_errors(bio_err);
490                         goto end;
491                 }
492                 if (dgst_config.sigopts) {
493                         char *sigopt;
494                         for (i = 0; i < sk_OPENSSL_STRING_num(
495                             dgst_config.sigopts); i++) {
496                                 sigopt = sk_OPENSSL_STRING_value(
497                                     dgst_config.sigopts, i);
498                                 if (pkey_ctrl_string(pctx, sigopt) <= 0) {
499                                         BIO_printf(bio_err,
500                                             "parameter error \"%s\"\n",
501                                             sigopt);
502                                         ERR_print_errors(bio_err);
503                                         goto end;
504                                 }
505                         }
506                 }
507         }
508         /* we use md as a filter, reading from 'in' */
509         else {
510                 if (dgst_config.md == NULL)
511                         dgst_config.md = EVP_sha256();
512                 if (!BIO_set_md(bmd, dgst_config.md)) {
513                         BIO_printf(bio_err, "Error setting digest %s\n", pname);
514                         ERR_print_errors(bio_err);
515                         goto end;
516                 }
517         }
518
519         if (dgst_config.sigfile && sigkey) {
520                 BIO *sigbio;
521                 siglen = EVP_PKEY_size(sigkey);
522                 sigbuf = malloc(siglen);
523                 if (sigbuf == NULL) {
524                         BIO_printf(bio_err, "out of memory\n");
525                         ERR_print_errors(bio_err);
526                         goto end;
527                 }
528                 sigbio = BIO_new_file(dgst_config.sigfile, "rb");
529                 if (!sigbio) {
530                         BIO_printf(bio_err, "Error opening signature file %s\n",
531                             dgst_config.sigfile);
532                         ERR_print_errors(bio_err);
533                         goto end;
534                 }
535                 siglen = BIO_read(sigbio, sigbuf, siglen);
536                 BIO_free(sigbio);
537                 if (siglen <= 0) {
538                         BIO_printf(bio_err, "Error reading signature file %s\n",
539                             dgst_config.sigfile);
540                         ERR_print_errors(bio_err);
541                         goto end;
542                 }
543         }
544         inp = BIO_push(bmd, in);
545
546         if (dgst_config.md == NULL) {
547                 EVP_MD_CTX *tctx;
548                 BIO_get_md_ctx(bmd, &tctx);
549                 dgst_config.md = EVP_MD_CTX_md(tctx);
550         }
551         if (argc == 0) {
552                 BIO_set_fp(in, stdin, BIO_NOCLOSE);
553                 err = do_fp(out, buf, inp, dgst_config.separator,
554                     dgst_config.out_bin, sigkey, sigbuf, siglen, NULL, NULL,
555                     "stdin", bmd);
556         } else {
557                 const char *md_name = NULL, *sig_name = NULL;
558                 if (!dgst_config.out_bin) {
559                         if (sigkey) {
560                                 const EVP_PKEY_ASN1_METHOD *ameth;
561                                 ameth = EVP_PKEY_get0_asn1(sigkey);
562                                 if (ameth)
563                                         EVP_PKEY_asn1_get0_info(NULL, NULL,
564                                             NULL, NULL, &sig_name, ameth);
565                         }
566                         md_name = EVP_MD_name(dgst_config.md);
567                 }
568                 err = 0;
569                 for (i = 0; i < argc; i++) {
570                         int r;
571                         if (BIO_read_filename(in, argv[i]) <= 0) {
572                                 perror(argv[i]);
573                                 err++;
574                                 continue;
575                         } else {
576                                 r = do_fp(out, buf, inp, dgst_config.separator,
577                                     dgst_config.out_bin, sigkey, sigbuf, siglen,
578                                     sig_name, md_name, argv[i], bmd);
579                         }
580                         if (r)
581                                 err = r;
582                         (void) BIO_reset(bmd);
583                 }
584         }
585
586  end:
587         freezero(buf, BUFSIZE);
588         BIO_free(in);
589         free(passin);
590         BIO_free_all(out);
591         EVP_PKEY_free(sigkey);
592         sk_OPENSSL_STRING_free(dgst_config.sigopts);
593         sk_OPENSSL_STRING_free(dgst_config.macopts);
594         free(sigbuf);
595         BIO_free(bmd);
596
597         return (err);
598 }
599
600 int
601 do_fp(BIO * out, unsigned char *buf, BIO * bp, int sep, int binout,
602     EVP_PKEY * key, unsigned char *sigin, int siglen,
603     const char *sig_name, const char *md_name,
604     const char *file, BIO * bmd)
605 {
606         size_t len;
607         int i;
608
609         for (;;) {
610                 i = BIO_read(bp, (char *) buf, BUFSIZE);
611                 if (i < 0) {
612                         BIO_printf(bio_err, "Read Error in %s\n", file);
613                         ERR_print_errors(bio_err);
614                         return 1;
615                 }
616                 if (i == 0)
617                         break;
618         }
619         if (sigin) {
620                 EVP_MD_CTX *ctx;
621                 BIO_get_md_ctx(bp, &ctx);
622                 i = EVP_DigestVerifyFinal(ctx, sigin, (unsigned int) siglen);
623                 if (i > 0)
624                         BIO_printf(out, "Verified OK\n");
625                 else if (i == 0) {
626                         BIO_printf(out, "Verification Failure\n");
627                         return 1;
628                 } else {
629                         BIO_printf(bio_err, "Error Verifying Data\n");
630                         ERR_print_errors(bio_err);
631                         return 1;
632                 }
633                 return 0;
634         }
635         if (key) {
636                 EVP_MD_CTX *ctx;
637                 BIO_get_md_ctx(bp, &ctx);
638                 len = BUFSIZE;
639                 if (!EVP_DigestSignFinal(ctx, buf, &len)) {
640                         BIO_printf(bio_err, "Error Signing Data\n");
641                         ERR_print_errors(bio_err);
642                         return 1;
643                 }
644         } else {
645                 len = BIO_gets(bp, (char *) buf, BUFSIZE);
646                 if ((int) len < 0) {
647                         ERR_print_errors(bio_err);
648                         return 1;
649                 }
650         }
651
652         if (binout)
653                 BIO_write(out, buf, len);
654         else if (sep == 2) {
655                 for (i = 0; i < (int) len; i++)
656                         BIO_printf(out, "%02x", buf[i]);
657                 BIO_printf(out, " *%s\n", file);
658         } else {
659                 if (sig_name)
660                         BIO_printf(out, "%s-%s(%s)= ", sig_name, md_name, file);
661                 else if (md_name)
662                         BIO_printf(out, "%s(%s)= ", md_name, file);
663                 else
664                         BIO_printf(out, "(%s)= ", file);
665                 for (i = 0; i < (int) len; i++) {
666                         if (sep && (i != 0))
667                                 BIO_printf(out, ":");
668                         BIO_printf(out, "%02x", buf[i]);
669                 }
670                 BIO_printf(out, "\n");
671         }
672         return 0;
673 }