1 /* $OpenBSD: dgst.c,v 1.18 2019/08/30 12:32:14 inoguchi 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 /* Skip clones */ 306 if (EVP_MD_flags(m) & EVP_MD_FLAG_PKEY_DIGEST) 307 return; 308 if (strchr(mname, ' ')) 309 mname = EVP_MD_name(m); 310 BIO_printf(arg, " -%-17s To use the %s message digest algorithm\n", 311 mname, mname); 312 } 313 314 static void 315 dgst_usage(void) 316 { 317 fprintf(stderr, "usage: dgst [-cdr] [-binary] [-digest] [-hex]"); 318 fprintf(stderr, " [-hmac key] [-keyform fmt]\n"); 319 fprintf(stderr, " [-mac algorithm] [-macopt nm:v] [-out file]"); 320 fprintf(stderr, " [-passin arg]\n"); 321 fprintf(stderr, " [-prverify file] [-sign file]"); 322 fprintf(stderr, " [-signature file]\n"); 323 fprintf(stderr, " [-sigopt nm:v] [-verify file] [file ...]\n\n"); 324 options_usage(dgst_options); 325 EVP_MD_do_all_sorted(list_md_fn, bio_err); 326 fprintf(stderr, "\n"); 327 } 328 329 int 330 dgst_main(int argc, char **argv) 331 { 332 unsigned char *buf = NULL; 333 int i, err = 1; 334 BIO *in = NULL, *inp; 335 BIO *bmd = NULL; 336 BIO *out = NULL; 337 #define PROG_NAME_SIZE 39 338 char pname[PROG_NAME_SIZE + 1]; 339 EVP_PKEY *sigkey = NULL; 340 unsigned char *sigbuf = NULL; 341 int siglen = 0; 342 char *passin = NULL; 343 344 if (single_execution) { 345 if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { 346 perror("pledge"); 347 exit(1); 348 } 349 } 350 351 if ((buf = malloc(BUFSIZE)) == NULL) { 352 BIO_printf(bio_err, "out of memory\n"); 353 goto end; 354 } 355 356 memset(&dgst_config, 0, sizeof(dgst_config)); 357 dgst_config.keyform = FORMAT_PEM; 358 dgst_config.out_bin = -1; 359 360 /* first check the program name */ 361 program_name(argv[0], pname, sizeof pname); 362 363 dgst_config.md = EVP_get_digestbyname(pname); 364 365 if (options_parse(argc, argv, dgst_options, NULL, 366 &dgst_config.argsused) != 0) { 367 dgst_usage(); 368 goto end; 369 } 370 argc -= dgst_config.argsused; 371 argv += dgst_config.argsused; 372 373 if (dgst_config.do_verify && !dgst_config.sigfile) { 374 BIO_printf(bio_err, 375 "No signature to verify: use the -signature option\n"); 376 goto end; 377 } 378 379 in = BIO_new(BIO_s_file()); 380 bmd = BIO_new(BIO_f_md()); 381 if (in == NULL || bmd == NULL) { 382 ERR_print_errors(bio_err); 383 goto end; 384 } 385 386 if (dgst_config.debug) { 387 BIO_set_callback(in, BIO_debug_callback); 388 /* needed for windows 3.1 */ 389 BIO_set_callback_arg(in, (char *) bio_err); 390 } 391 if (!app_passwd(bio_err, dgst_config.passargin, NULL, &passin, NULL)) { 392 BIO_printf(bio_err, "Error getting password\n"); 393 goto end; 394 } 395 if (dgst_config.out_bin == -1) { 396 if (dgst_config.keyfile) 397 dgst_config.out_bin = 1; 398 else 399 dgst_config.out_bin = 0; 400 } 401 402 if (dgst_config.outfile) { 403 if (dgst_config.out_bin) 404 out = BIO_new_file(dgst_config.outfile, "wb"); 405 else 406 out = BIO_new_file(dgst_config.outfile, "w"); 407 } else { 408 out = BIO_new_fp(stdout, BIO_NOCLOSE); 409 } 410 411 if (!out) { 412 BIO_printf(bio_err, "Error opening output file %s\n", 413 dgst_config.outfile ? dgst_config.outfile : "(stdout)"); 414 ERR_print_errors(bio_err); 415 goto end; 416 } 417 if ((!!dgst_config.mac_name + !!dgst_config.keyfile + 418 !!dgst_config.hmac_key) > 1) { 419 BIO_printf(bio_err, 420 "MAC and Signing key cannot both be specified\n"); 421 goto end; 422 } 423 if (dgst_config.keyfile) { 424 if (dgst_config.want_pub) 425 sigkey = load_pubkey(bio_err, dgst_config.keyfile, 426 dgst_config.keyform, 0, NULL, "key file"); 427 else 428 sigkey = load_key(bio_err, dgst_config.keyfile, 429 dgst_config.keyform, 0, passin, "key file"); 430 if (!sigkey) { 431 /* 432 * load_[pub]key() has already printed an appropriate 433 * message 434 */ 435 goto end; 436 } 437 } 438 if (dgst_config.mac_name) { 439 EVP_PKEY_CTX *mac_ctx = NULL; 440 int r = 0; 441 if (!init_gen_str(bio_err, &mac_ctx, dgst_config.mac_name, 0)) 442 goto mac_end; 443 if (dgst_config.macopts) { 444 char *macopt; 445 for (i = 0; i < sk_OPENSSL_STRING_num( 446 dgst_config.macopts); i++) { 447 macopt = sk_OPENSSL_STRING_value( 448 dgst_config.macopts, i); 449 if (pkey_ctrl_string(mac_ctx, macopt) <= 0) { 450 BIO_printf(bio_err, 451 "MAC parameter error \"%s\"\n", 452 macopt); 453 ERR_print_errors(bio_err); 454 goto mac_end; 455 } 456 } 457 } 458 if (EVP_PKEY_keygen(mac_ctx, &sigkey) <= 0) { 459 BIO_puts(bio_err, "Error generating key\n"); 460 ERR_print_errors(bio_err); 461 goto mac_end; 462 } 463 r = 1; 464 mac_end: 465 EVP_PKEY_CTX_free(mac_ctx); 466 if (r == 0) 467 goto end; 468 } 469 if (dgst_config.hmac_key) { 470 sigkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, 471 (unsigned char *) dgst_config.hmac_key, -1); 472 if (!sigkey) 473 goto end; 474 } 475 if (sigkey) { 476 EVP_MD_CTX *mctx = NULL; 477 EVP_PKEY_CTX *pctx = NULL; 478 int r; 479 if (!BIO_get_md_ctx(bmd, &mctx)) { 480 BIO_printf(bio_err, "Error getting context\n"); 481 ERR_print_errors(bio_err); 482 goto end; 483 } 484 if (dgst_config.do_verify) 485 r = EVP_DigestVerifyInit(mctx, &pctx, dgst_config.md, 486 NULL, sigkey); 487 else 488 r = EVP_DigestSignInit(mctx, &pctx, dgst_config.md, 489 NULL, sigkey); 490 if (!r) { 491 BIO_printf(bio_err, "Error setting context\n"); 492 ERR_print_errors(bio_err); 493 goto end; 494 } 495 if (dgst_config.sigopts) { 496 char *sigopt; 497 for (i = 0; i < sk_OPENSSL_STRING_num( 498 dgst_config.sigopts); i++) { 499 sigopt = sk_OPENSSL_STRING_value( 500 dgst_config.sigopts, i); 501 if (pkey_ctrl_string(pctx, sigopt) <= 0) { 502 BIO_printf(bio_err, 503 "parameter error \"%s\"\n", 504 sigopt); 505 ERR_print_errors(bio_err); 506 goto end; 507 } 508 } 509 } 510 } 511 /* we use md as a filter, reading from 'in' */ 512 else { 513 if (dgst_config.md == NULL) 514 dgst_config.md = EVP_sha256(); 515 if (!BIO_set_md(bmd, dgst_config.md)) { 516 BIO_printf(bio_err, "Error setting digest %s\n", pname); 517 ERR_print_errors(bio_err); 518 goto end; 519 } 520 } 521 522 if (dgst_config.sigfile && sigkey) { 523 BIO *sigbio; 524 siglen = EVP_PKEY_size(sigkey); 525 sigbuf = malloc(siglen); 526 if (sigbuf == NULL) { 527 BIO_printf(bio_err, "out of memory\n"); 528 ERR_print_errors(bio_err); 529 goto end; 530 } 531 sigbio = BIO_new_file(dgst_config.sigfile, "rb"); 532 if (!sigbio) { 533 BIO_printf(bio_err, "Error opening signature file %s\n", 534 dgst_config.sigfile); 535 ERR_print_errors(bio_err); 536 goto end; 537 } 538 siglen = BIO_read(sigbio, sigbuf, siglen); 539 BIO_free(sigbio); 540 if (siglen <= 0) { 541 BIO_printf(bio_err, "Error reading signature file %s\n", 542 dgst_config.sigfile); 543 ERR_print_errors(bio_err); 544 goto end; 545 } 546 } 547 inp = BIO_push(bmd, in); 548 549 if (dgst_config.md == NULL) { 550 EVP_MD_CTX *tctx; 551 BIO_get_md_ctx(bmd, &tctx); 552 dgst_config.md = EVP_MD_CTX_md(tctx); 553 } 554 if (argc == 0) { 555 BIO_set_fp(in, stdin, BIO_NOCLOSE); 556 err = do_fp(out, buf, inp, dgst_config.separator, 557 dgst_config.out_bin, sigkey, sigbuf, siglen, NULL, NULL, 558 "stdin", bmd); 559 } else { 560 const char *md_name = NULL, *sig_name = NULL; 561 if (!dgst_config.out_bin) { 562 if (sigkey) { 563 const EVP_PKEY_ASN1_METHOD *ameth; 564 ameth = EVP_PKEY_get0_asn1(sigkey); 565 if (ameth) 566 EVP_PKEY_asn1_get0_info(NULL, NULL, 567 NULL, NULL, &sig_name, ameth); 568 } 569 md_name = EVP_MD_name(dgst_config.md); 570 } 571 err = 0; 572 for (i = 0; i < argc; i++) { 573 int r; 574 if (BIO_read_filename(in, argv[i]) <= 0) { 575 perror(argv[i]); 576 err++; 577 continue; 578 } else { 579 r = do_fp(out, buf, inp, dgst_config.separator, 580 dgst_config.out_bin, sigkey, sigbuf, siglen, 581 sig_name, md_name, argv[i], bmd); 582 } 583 if (r) 584 err = r; 585 (void) BIO_reset(bmd); 586 } 587 } 588 589 end: 590 freezero(buf, BUFSIZE); 591 BIO_free(in); 592 free(passin); 593 BIO_free_all(out); 594 EVP_PKEY_free(sigkey); 595 sk_OPENSSL_STRING_free(dgst_config.sigopts); 596 sk_OPENSSL_STRING_free(dgst_config.macopts); 597 free(sigbuf); 598 BIO_free(bmd); 599 600 return (err); 601 } 602 603 int 604 do_fp(BIO * out, unsigned char *buf, BIO * bp, int sep, int binout, 605 EVP_PKEY * key, unsigned char *sigin, int siglen, 606 const char *sig_name, const char *md_name, 607 const char *file, BIO * bmd) 608 { 609 size_t len; 610 int i; 611 612 for (;;) { 613 i = BIO_read(bp, (char *) buf, BUFSIZE); 614 if (i < 0) { 615 BIO_printf(bio_err, "Read Error in %s\n", file); 616 ERR_print_errors(bio_err); 617 return 1; 618 } 619 if (i == 0) 620 break; 621 } 622 if (sigin) { 623 EVP_MD_CTX *ctx; 624 BIO_get_md_ctx(bp, &ctx); 625 i = EVP_DigestVerifyFinal(ctx, sigin, (unsigned int) siglen); 626 if (i > 0) 627 BIO_printf(out, "Verified OK\n"); 628 else if (i == 0) { 629 BIO_printf(out, "Verification Failure\n"); 630 return 1; 631 } else { 632 BIO_printf(bio_err, "Error Verifying Data\n"); 633 ERR_print_errors(bio_err); 634 return 1; 635 } 636 return 0; 637 } 638 if (key) { 639 EVP_MD_CTX *ctx; 640 BIO_get_md_ctx(bp, &ctx); 641 len = BUFSIZE; 642 if (!EVP_DigestSignFinal(ctx, buf, &len)) { 643 BIO_printf(bio_err, "Error Signing Data\n"); 644 ERR_print_errors(bio_err); 645 return 1; 646 } 647 } else { 648 len = BIO_gets(bp, (char *) buf, BUFSIZE); 649 if ((int) len < 0) { 650 ERR_print_errors(bio_err); 651 return 1; 652 } 653 } 654 655 if (binout) 656 BIO_write(out, buf, len); 657 else if (sep == 2) { 658 for (i = 0; i < (int) len; i++) 659 BIO_printf(out, "%02x", buf[i]); 660 BIO_printf(out, " *%s\n", file); 661 } else { 662 if (sig_name) 663 BIO_printf(out, "%s-%s(%s)= ", sig_name, md_name, file); 664 else if (md_name) 665 BIO_printf(out, "%s(%s)= ", md_name, file); 666 else 667 BIO_printf(out, "(%s)= ", file); 668 for (i = 0; i < (int) len; i++) { 669 if (sep && (i != 0)) 670 BIO_printf(out, ":"); 671 BIO_printf(out, "%02x", buf[i]); 672 } 673 BIO_printf(out, "\n"); 674 } 675 return 0; 676 } 677