Annotation of src/usr.bin/openssl/smime.c, Revision 1.1
1.1 ! jsing 1: /* $OpenBSD: smime.c,v 1.28 2014/07/14 00:35:10 deraadt Exp $ */
! 2: /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
! 3: * project.
! 4: */
! 5: /* ====================================================================
! 6: * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: *
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: *
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in
! 17: * the documentation and/or other materials provided with the
! 18: * distribution.
! 19: *
! 20: * 3. All advertising materials mentioning features or use of this
! 21: * software must display the following acknowledgment:
! 22: * "This product includes software developed by the OpenSSL Project
! 23: * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
! 24: *
! 25: * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
! 26: * endorse or promote products derived from this software without
! 27: * prior written permission. For written permission, please contact
! 28: * licensing@OpenSSL.org.
! 29: *
! 30: * 5. Products derived from this software may not be called "OpenSSL"
! 31: * nor may "OpenSSL" appear in their names without prior written
! 32: * permission of the OpenSSL Project.
! 33: *
! 34: * 6. Redistributions of any form whatsoever must retain the following
! 35: * acknowledgment:
! 36: * "This product includes software developed by the OpenSSL Project
! 37: * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
! 38: *
! 39: * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
! 40: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 41: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 42: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
! 43: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
! 44: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 45: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
! 46: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 47: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 48: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 49: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
! 50: * OF THE POSSIBILITY OF SUCH DAMAGE.
! 51: * ====================================================================
! 52: *
! 53: * This product includes cryptographic software written by Eric Young
! 54: * (eay@cryptsoft.com). This product includes software written by Tim
! 55: * Hudson (tjh@cryptsoft.com).
! 56: *
! 57: */
! 58:
! 59: /* S/MIME utility function */
! 60:
! 61: #include <stdio.h>
! 62: #include <string.h>
! 63:
! 64: #include "apps.h"
! 65:
! 66: #include <openssl/crypto.h>
! 67: #include <openssl/err.h>
! 68: #include <openssl/pem.h>
! 69: #include <openssl/x509_vfy.h>
! 70: #include <openssl/x509v3.h>
! 71:
! 72: static int save_certs(char *signerfile, STACK_OF(X509) * signers);
! 73: static int smime_cb(int ok, X509_STORE_CTX * ctx);
! 74:
! 75: #define SMIME_OP 0x10
! 76: #define SMIME_IP 0x20
! 77: #define SMIME_SIGNERS 0x40
! 78: #define SMIME_ENCRYPT (1 | SMIME_OP)
! 79: #define SMIME_DECRYPT (2 | SMIME_IP)
! 80: #define SMIME_SIGN (3 | SMIME_OP | SMIME_SIGNERS)
! 81: #define SMIME_VERIFY (4 | SMIME_IP)
! 82: #define SMIME_PK7OUT (5 | SMIME_IP | SMIME_OP)
! 83: #define SMIME_RESIGN (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
! 84:
! 85: int smime_main(int, char **);
! 86:
! 87: int
! 88: smime_main(int argc, char **argv)
! 89: {
! 90: ENGINE *e = NULL;
! 91: int operation = 0;
! 92: int ret = 0;
! 93: char **args;
! 94: const char *inmode = "r", *outmode = "w";
! 95: char *infile = NULL, *outfile = NULL;
! 96: char *signerfile = NULL, *recipfile = NULL;
! 97: STACK_OF(OPENSSL_STRING) * sksigners = NULL, *skkeys = NULL;
! 98: char *certfile = NULL, *keyfile = NULL, *contfile = NULL;
! 99: const EVP_CIPHER *cipher = NULL;
! 100: PKCS7 *p7 = NULL;
! 101: X509_STORE *store = NULL;
! 102: X509 *cert = NULL, *recip = NULL, *signer = NULL;
! 103: EVP_PKEY *key = NULL;
! 104: STACK_OF(X509) * encerts = NULL, *other = NULL;
! 105: BIO *in = NULL, *out = NULL, *indata = NULL;
! 106: int badarg = 0;
! 107: int flags = PKCS7_DETACHED;
! 108: char *to = NULL, *from = NULL, *subject = NULL;
! 109: char *CAfile = NULL, *CApath = NULL;
! 110: char *passargin = NULL, *passin = NULL;
! 111: int indef = 0;
! 112: const EVP_MD *sign_md = NULL;
! 113: int informat = FORMAT_SMIME, outformat = FORMAT_SMIME;
! 114: int keyform = FORMAT_PEM;
! 115: #ifndef OPENSSL_NO_ENGINE
! 116: char *engine = NULL;
! 117: #endif
! 118:
! 119: X509_VERIFY_PARAM *vpm = NULL;
! 120:
! 121: args = argv + 1;
! 122: ret = 1;
! 123:
! 124: while (!badarg && *args && *args[0] == '-') {
! 125: if (!strcmp(*args, "-encrypt"))
! 126: operation = SMIME_ENCRYPT;
! 127: else if (!strcmp(*args, "-decrypt"))
! 128: operation = SMIME_DECRYPT;
! 129: else if (!strcmp(*args, "-sign"))
! 130: operation = SMIME_SIGN;
! 131: else if (!strcmp(*args, "-resign"))
! 132: operation = SMIME_RESIGN;
! 133: else if (!strcmp(*args, "-verify"))
! 134: operation = SMIME_VERIFY;
! 135: else if (!strcmp(*args, "-pk7out"))
! 136: operation = SMIME_PK7OUT;
! 137: #ifndef OPENSSL_NO_DES
! 138: else if (!strcmp(*args, "-des3"))
! 139: cipher = EVP_des_ede3_cbc();
! 140: else if (!strcmp(*args, "-des"))
! 141: cipher = EVP_des_cbc();
! 142: #endif
! 143: #ifndef OPENSSL_NO_RC2
! 144: else if (!strcmp(*args, "-rc2-40"))
! 145: cipher = EVP_rc2_40_cbc();
! 146: else if (!strcmp(*args, "-rc2-128"))
! 147: cipher = EVP_rc2_cbc();
! 148: else if (!strcmp(*args, "-rc2-64"))
! 149: cipher = EVP_rc2_64_cbc();
! 150: #endif
! 151: #ifndef OPENSSL_NO_AES
! 152: else if (!strcmp(*args, "-aes128"))
! 153: cipher = EVP_aes_128_cbc();
! 154: else if (!strcmp(*args, "-aes192"))
! 155: cipher = EVP_aes_192_cbc();
! 156: else if (!strcmp(*args, "-aes256"))
! 157: cipher = EVP_aes_256_cbc();
! 158: #endif
! 159: #ifndef OPENSSL_NO_CAMELLIA
! 160: else if (!strcmp(*args, "-camellia128"))
! 161: cipher = EVP_camellia_128_cbc();
! 162: else if (!strcmp(*args, "-camellia192"))
! 163: cipher = EVP_camellia_192_cbc();
! 164: else if (!strcmp(*args, "-camellia256"))
! 165: cipher = EVP_camellia_256_cbc();
! 166: #endif
! 167: else if (!strcmp(*args, "-text"))
! 168: flags |= PKCS7_TEXT;
! 169: else if (!strcmp(*args, "-nointern"))
! 170: flags |= PKCS7_NOINTERN;
! 171: else if (!strcmp(*args, "-noverify"))
! 172: flags |= PKCS7_NOVERIFY;
! 173: else if (!strcmp(*args, "-nochain"))
! 174: flags |= PKCS7_NOCHAIN;
! 175: else if (!strcmp(*args, "-nocerts"))
! 176: flags |= PKCS7_NOCERTS;
! 177: else if (!strcmp(*args, "-noattr"))
! 178: flags |= PKCS7_NOATTR;
! 179: else if (!strcmp(*args, "-nodetach"))
! 180: flags &= ~PKCS7_DETACHED;
! 181: else if (!strcmp(*args, "-nosmimecap"))
! 182: flags |= PKCS7_NOSMIMECAP;
! 183: else if (!strcmp(*args, "-binary"))
! 184: flags |= PKCS7_BINARY;
! 185: else if (!strcmp(*args, "-nosigs"))
! 186: flags |= PKCS7_NOSIGS;
! 187: else if (!strcmp(*args, "-stream"))
! 188: indef = 1;
! 189: else if (!strcmp(*args, "-indef"))
! 190: indef = 1;
! 191: else if (!strcmp(*args, "-noindef"))
! 192: indef = 0;
! 193: else if (!strcmp(*args, "-nooldmime"))
! 194: flags |= PKCS7_NOOLDMIMETYPE;
! 195: else if (!strcmp(*args, "-crlfeol"))
! 196: flags |= PKCS7_CRLFEOL;
! 197: #ifndef OPENSSL_NO_ENGINE
! 198: else if (!strcmp(*args, "-engine")) {
! 199: if (!args[1])
! 200: goto argerr;
! 201: engine = *++args;
! 202: }
! 203: #endif
! 204: else if (!strcmp(*args, "-passin")) {
! 205: if (!args[1])
! 206: goto argerr;
! 207: passargin = *++args;
! 208: } else if (!strcmp(*args, "-to")) {
! 209: if (!args[1])
! 210: goto argerr;
! 211: to = *++args;
! 212: } else if (!strcmp(*args, "-from")) {
! 213: if (!args[1])
! 214: goto argerr;
! 215: from = *++args;
! 216: } else if (!strcmp(*args, "-subject")) {
! 217: if (!args[1])
! 218: goto argerr;
! 219: subject = *++args;
! 220: } else if (!strcmp(*args, "-signer")) {
! 221: if (!args[1])
! 222: goto argerr;
! 223: /* If previous -signer argument add signer to list */
! 224:
! 225: if (signerfile) {
! 226: if (!sksigners)
! 227: sksigners = sk_OPENSSL_STRING_new_null();
! 228: sk_OPENSSL_STRING_push(sksigners, signerfile);
! 229: if (!keyfile)
! 230: keyfile = signerfile;
! 231: if (!skkeys)
! 232: skkeys = sk_OPENSSL_STRING_new_null();
! 233: sk_OPENSSL_STRING_push(skkeys, keyfile);
! 234: keyfile = NULL;
! 235: }
! 236: signerfile = *++args;
! 237: } else if (!strcmp(*args, "-recip")) {
! 238: if (!args[1])
! 239: goto argerr;
! 240: recipfile = *++args;
! 241: } else if (!strcmp(*args, "-md")) {
! 242: if (!args[1])
! 243: goto argerr;
! 244: sign_md = EVP_get_digestbyname(*++args);
! 245: if (sign_md == NULL) {
! 246: BIO_printf(bio_err, "Unknown digest %s\n",
! 247: *args);
! 248: goto argerr;
! 249: }
! 250: } else if (!strcmp(*args, "-inkey")) {
! 251: if (!args[1])
! 252: goto argerr;
! 253: /* If previous -inkey arument add signer to list */
! 254: if (keyfile) {
! 255: if (!signerfile) {
! 256: BIO_puts(bio_err, "Illegal -inkey without -signer\n");
! 257: goto argerr;
! 258: }
! 259: if (!sksigners)
! 260: sksigners = sk_OPENSSL_STRING_new_null();
! 261: sk_OPENSSL_STRING_push(sksigners, signerfile);
! 262: signerfile = NULL;
! 263: if (!skkeys)
! 264: skkeys = sk_OPENSSL_STRING_new_null();
! 265: sk_OPENSSL_STRING_push(skkeys, keyfile);
! 266: }
! 267: keyfile = *++args;
! 268: } else if (!strcmp(*args, "-keyform")) {
! 269: if (!args[1])
! 270: goto argerr;
! 271: keyform = str2fmt(*++args);
! 272: } else if (!strcmp(*args, "-certfile")) {
! 273: if (!args[1])
! 274: goto argerr;
! 275: certfile = *++args;
! 276: } else if (!strcmp(*args, "-CAfile")) {
! 277: if (!args[1])
! 278: goto argerr;
! 279: CAfile = *++args;
! 280: } else if (!strcmp(*args, "-CApath")) {
! 281: if (!args[1])
! 282: goto argerr;
! 283: CApath = *++args;
! 284: } else if (!strcmp(*args, "-in")) {
! 285: if (!args[1])
! 286: goto argerr;
! 287: infile = *++args;
! 288: } else if (!strcmp(*args, "-inform")) {
! 289: if (!args[1])
! 290: goto argerr;
! 291: informat = str2fmt(*++args);
! 292: } else if (!strcmp(*args, "-outform")) {
! 293: if (!args[1])
! 294: goto argerr;
! 295: outformat = str2fmt(*++args);
! 296: } else if (!strcmp(*args, "-out")) {
! 297: if (!args[1])
! 298: goto argerr;
! 299: outfile = *++args;
! 300: } else if (!strcmp(*args, "-content")) {
! 301: if (!args[1])
! 302: goto argerr;
! 303: contfile = *++args;
! 304: } else if (args_verify(&args, NULL, &badarg, bio_err, &vpm))
! 305: continue;
! 306: else if ((cipher = EVP_get_cipherbyname(*args + 1)) == NULL)
! 307: badarg = 1;
! 308: args++;
! 309: }
! 310:
! 311: if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) {
! 312: BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
! 313: goto argerr;
! 314: }
! 315: if (operation & SMIME_SIGNERS) {
! 316: /* Check to see if any final signer needs to be appended */
! 317: if (keyfile && !signerfile) {
! 318: BIO_puts(bio_err, "Illegal -inkey without -signer\n");
! 319: goto argerr;
! 320: }
! 321: if (signerfile) {
! 322: if (!sksigners)
! 323: sksigners = sk_OPENSSL_STRING_new_null();
! 324: sk_OPENSSL_STRING_push(sksigners, signerfile);
! 325: if (!skkeys)
! 326: skkeys = sk_OPENSSL_STRING_new_null();
! 327: if (!keyfile)
! 328: keyfile = signerfile;
! 329: sk_OPENSSL_STRING_push(skkeys, keyfile);
! 330: }
! 331: if (!sksigners) {
! 332: BIO_printf(bio_err, "No signer certificate specified\n");
! 333: badarg = 1;
! 334: }
! 335: signerfile = NULL;
! 336: keyfile = NULL;
! 337: } else if (operation == SMIME_DECRYPT) {
! 338: if (!recipfile && !keyfile) {
! 339: BIO_printf(bio_err, "No recipient certificate or key specified\n");
! 340: badarg = 1;
! 341: }
! 342: } else if (operation == SMIME_ENCRYPT) {
! 343: if (!*args) {
! 344: BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
! 345: badarg = 1;
! 346: }
! 347: } else if (!operation)
! 348: badarg = 1;
! 349:
! 350: if (badarg) {
! 351: argerr:
! 352: BIO_printf(bio_err, "Usage smime [options] cert.pem ...\n");
! 353: BIO_printf(bio_err, "where options are\n");
! 354: BIO_printf(bio_err, "-encrypt encrypt message\n");
! 355: BIO_printf(bio_err, "-decrypt decrypt encrypted message\n");
! 356: BIO_printf(bio_err, "-sign sign message\n");
! 357: BIO_printf(bio_err, "-verify verify signed message\n");
! 358: BIO_printf(bio_err, "-pk7out output PKCS#7 structure\n");
! 359: #ifndef OPENSSL_NO_DES
! 360: BIO_printf(bio_err, "-des3 encrypt with triple DES\n");
! 361: BIO_printf(bio_err, "-des encrypt with DES\n");
! 362: #endif
! 363: #ifndef OPENSSL_NO_RC2
! 364: BIO_printf(bio_err, "-rc2-40 encrypt with RC2-40 (default)\n");
! 365: BIO_printf(bio_err, "-rc2-64 encrypt with RC2-64\n");
! 366: BIO_printf(bio_err, "-rc2-128 encrypt with RC2-128\n");
! 367: #endif
! 368: #ifndef OPENSSL_NO_AES
! 369: BIO_printf(bio_err, "-aes128, -aes192, -aes256\n");
! 370: BIO_printf(bio_err, " encrypt PEM output with cbc aes\n");
! 371: #endif
! 372: #ifndef OPENSSL_NO_CAMELLIA
! 373: BIO_printf(bio_err, "-camellia128, -camellia192, -camellia256\n");
! 374: BIO_printf(bio_err, " encrypt PEM output with cbc camellia\n");
! 375: #endif
! 376: BIO_printf(bio_err, "-nointern don't search certificates in message for signer\n");
! 377: BIO_printf(bio_err, "-nosigs don't verify message signature\n");
! 378: BIO_printf(bio_err, "-noverify don't verify signers certificate\n");
! 379: BIO_printf(bio_err, "-nocerts don't include signers certificate when signing\n");
! 380: BIO_printf(bio_err, "-nodetach use opaque signing\n");
! 381: BIO_printf(bio_err, "-noattr don't include any signed attributes\n");
! 382: BIO_printf(bio_err, "-binary don't translate message to text\n");
! 383: BIO_printf(bio_err, "-certfile file other certificates file\n");
! 384: BIO_printf(bio_err, "-signer file signer certificate file\n");
! 385: BIO_printf(bio_err, "-recip file recipient certificate file for decryption\n");
! 386: BIO_printf(bio_err, "-in file input file\n");
! 387: BIO_printf(bio_err, "-inform arg input format SMIME (default), PEM or DER\n");
! 388: BIO_printf(bio_err, "-inkey file input private key (if not signer or recipient)\n");
! 389: BIO_printf(bio_err, "-keyform arg input private key format (PEM or ENGINE)\n");
! 390: BIO_printf(bio_err, "-out file output file\n");
! 391: BIO_printf(bio_err, "-outform arg output format SMIME (default), PEM or DER\n");
! 392: BIO_printf(bio_err, "-content file supply or override content for detached signature\n");
! 393: BIO_printf(bio_err, "-to addr to address\n");
! 394: BIO_printf(bio_err, "-from ad from address\n");
! 395: BIO_printf(bio_err, "-subject s subject\n");
! 396: BIO_printf(bio_err, "-text include or delete text MIME headers\n");
! 397: BIO_printf(bio_err, "-CApath dir trusted certificates directory\n");
! 398: BIO_printf(bio_err, "-CAfile file trusted certificates file\n");
! 399: BIO_printf(bio_err, "-crl_check check revocation status of signer's certificate using CRLs\n");
! 400: BIO_printf(bio_err, "-crl_check_all check revocation status of signer's certificate chain using CRLs\n");
! 401: #ifndef OPENSSL_NO_ENGINE
! 402: BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n");
! 403: #endif
! 404: BIO_printf(bio_err, "-passin arg input file pass phrase source\n");
! 405: BIO_printf(bio_err, "cert.pem recipient certificate(s) for encryption\n");
! 406: goto end;
! 407: }
! 408: #ifndef OPENSSL_NO_ENGINE
! 409: e = setup_engine(bio_err, engine, 0);
! 410: #endif
! 411:
! 412: if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
! 413: BIO_printf(bio_err, "Error getting password\n");
! 414: goto end;
! 415: }
! 416: ret = 2;
! 417:
! 418: if (!(operation & SMIME_SIGNERS))
! 419: flags &= ~PKCS7_DETACHED;
! 420:
! 421: if (operation & SMIME_OP) {
! 422: if (outformat == FORMAT_ASN1)
! 423: outmode = "wb";
! 424: } else {
! 425: if (flags & PKCS7_BINARY)
! 426: outmode = "wb";
! 427: }
! 428:
! 429: if (operation & SMIME_IP) {
! 430: if (informat == FORMAT_ASN1)
! 431: inmode = "rb";
! 432: } else {
! 433: if (flags & PKCS7_BINARY)
! 434: inmode = "rb";
! 435: }
! 436:
! 437: if (operation == SMIME_ENCRYPT) {
! 438: if (!cipher) {
! 439: #ifndef OPENSSL_NO_RC2
! 440: cipher = EVP_rc2_40_cbc();
! 441: #else
! 442: BIO_printf(bio_err, "No cipher selected\n");
! 443: goto end;
! 444: #endif
! 445: }
! 446: encerts = sk_X509_new_null();
! 447: while (*args) {
! 448: if (!(cert = load_cert(bio_err, *args, FORMAT_PEM,
! 449: NULL, e, "recipient certificate file"))) {
! 450: #if 0 /* An appropriate message is already printed */
! 451: BIO_printf(bio_err, "Can't read recipient certificate file %s\n", *args);
! 452: #endif
! 453: goto end;
! 454: }
! 455: sk_X509_push(encerts, cert);
! 456: cert = NULL;
! 457: args++;
! 458: }
! 459: }
! 460: if (certfile) {
! 461: if (!(other = load_certs(bio_err, certfile, FORMAT_PEM, NULL,
! 462: e, "certificate file"))) {
! 463: ERR_print_errors(bio_err);
! 464: goto end;
! 465: }
! 466: }
! 467: if (recipfile && (operation == SMIME_DECRYPT)) {
! 468: if (!(recip = load_cert(bio_err, recipfile, FORMAT_PEM, NULL,
! 469: e, "recipient certificate file"))) {
! 470: ERR_print_errors(bio_err);
! 471: goto end;
! 472: }
! 473: }
! 474: if (operation == SMIME_DECRYPT) {
! 475: if (!keyfile)
! 476: keyfile = recipfile;
! 477: } else if (operation == SMIME_SIGN) {
! 478: if (!keyfile)
! 479: keyfile = signerfile;
! 480: } else
! 481: keyfile = NULL;
! 482:
! 483: if (keyfile) {
! 484: key = load_key(bio_err, keyfile, keyform, 0, passin, e,
! 485: "signing key file");
! 486: if (!key)
! 487: goto end;
! 488: }
! 489: if (infile) {
! 490: if (!(in = BIO_new_file(infile, inmode))) {
! 491: BIO_printf(bio_err,
! 492: "Can't open input file %s\n", infile);
! 493: goto end;
! 494: }
! 495: } else
! 496: in = BIO_new_fp(stdin, BIO_NOCLOSE);
! 497:
! 498: if (operation & SMIME_IP) {
! 499: if (informat == FORMAT_SMIME)
! 500: p7 = SMIME_read_PKCS7(in, &indata);
! 501: else if (informat == FORMAT_PEM)
! 502: p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
! 503: else if (informat == FORMAT_ASN1)
! 504: p7 = d2i_PKCS7_bio(in, NULL);
! 505: else {
! 506: BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
! 507: goto end;
! 508: }
! 509:
! 510: if (!p7) {
! 511: BIO_printf(bio_err, "Error reading S/MIME message\n");
! 512: goto end;
! 513: }
! 514: if (contfile) {
! 515: BIO_free(indata);
! 516: if (!(indata = BIO_new_file(contfile, "rb"))) {
! 517: BIO_printf(bio_err, "Can't read content file %s\n", contfile);
! 518: goto end;
! 519: }
! 520: }
! 521: }
! 522: if (outfile) {
! 523: if (!(out = BIO_new_file(outfile, outmode))) {
! 524: BIO_printf(bio_err,
! 525: "Can't open output file %s\n", outfile);
! 526: goto end;
! 527: }
! 528: } else {
! 529: out = BIO_new_fp(stdout, BIO_NOCLOSE);
! 530: }
! 531:
! 532: if (operation == SMIME_VERIFY) {
! 533: if (!(store = setup_verify(bio_err, CAfile, CApath)))
! 534: goto end;
! 535: X509_STORE_set_verify_cb(store, smime_cb);
! 536: if (vpm)
! 537: X509_STORE_set1_param(store, vpm);
! 538: }
! 539: ret = 3;
! 540:
! 541: if (operation == SMIME_ENCRYPT) {
! 542: if (indef)
! 543: flags |= PKCS7_STREAM;
! 544: p7 = PKCS7_encrypt(encerts, in, cipher, flags);
! 545: } else if (operation & SMIME_SIGNERS) {
! 546: int i;
! 547: /*
! 548: * If detached data content we only enable streaming if
! 549: * S/MIME output format.
! 550: */
! 551: if (operation == SMIME_SIGN) {
! 552: if (flags & PKCS7_DETACHED) {
! 553: if (outformat == FORMAT_SMIME)
! 554: flags |= PKCS7_STREAM;
! 555: } else if (indef)
! 556: flags |= PKCS7_STREAM;
! 557: flags |= PKCS7_PARTIAL;
! 558: p7 = PKCS7_sign(NULL, NULL, other, in, flags);
! 559: if (!p7)
! 560: goto end;
! 561: } else
! 562: flags |= PKCS7_REUSE_DIGEST;
! 563: for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) {
! 564: signerfile = sk_OPENSSL_STRING_value(sksigners, i);
! 565: keyfile = sk_OPENSSL_STRING_value(skkeys, i);
! 566: signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL,
! 567: e, "signer certificate");
! 568: if (!signer)
! 569: goto end;
! 570: key = load_key(bio_err, keyfile, keyform, 0, passin, e,
! 571: "signing key file");
! 572: if (!key)
! 573: goto end;
! 574: if (!PKCS7_sign_add_signer(p7, signer, key,
! 575: sign_md, flags))
! 576: goto end;
! 577: X509_free(signer);
! 578: signer = NULL;
! 579: EVP_PKEY_free(key);
! 580: key = NULL;
! 581: }
! 582: /* If not streaming or resigning finalize structure */
! 583: if ((operation == SMIME_SIGN) && !(flags & PKCS7_STREAM)) {
! 584: if (!PKCS7_final(p7, in, flags))
! 585: goto end;
! 586: }
! 587: }
! 588: if (!p7) {
! 589: BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
! 590: goto end;
! 591: }
! 592: ret = 4;
! 593: if (operation == SMIME_DECRYPT) {
! 594: if (!PKCS7_decrypt(p7, key, recip, out, flags)) {
! 595: BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n");
! 596: goto end;
! 597: }
! 598: } else if (operation == SMIME_VERIFY) {
! 599: STACK_OF(X509) * signers;
! 600: if (PKCS7_verify(p7, other, store, indata, out, flags))
! 601: BIO_printf(bio_err, "Verification successful\n");
! 602: else {
! 603: BIO_printf(bio_err, "Verification failure\n");
! 604: goto end;
! 605: }
! 606: signers = PKCS7_get0_signers(p7, other, flags);
! 607: if (!save_certs(signerfile, signers)) {
! 608: BIO_printf(bio_err, "Error writing signers to %s\n",
! 609: signerfile);
! 610: ret = 5;
! 611: goto end;
! 612: }
! 613: sk_X509_free(signers);
! 614: } else if (operation == SMIME_PK7OUT)
! 615: PEM_write_bio_PKCS7(out, p7);
! 616: else {
! 617: if (to)
! 618: BIO_printf(out, "To: %s\n", to);
! 619: if (from)
! 620: BIO_printf(out, "From: %s\n", from);
! 621: if (subject)
! 622: BIO_printf(out, "Subject: %s\n", subject);
! 623: if (outformat == FORMAT_SMIME) {
! 624: if (operation == SMIME_RESIGN)
! 625: SMIME_write_PKCS7(out, p7, indata, flags);
! 626: else
! 627: SMIME_write_PKCS7(out, p7, in, flags);
! 628: } else if (outformat == FORMAT_PEM)
! 629: PEM_write_bio_PKCS7_stream(out, p7, in, flags);
! 630: else if (outformat == FORMAT_ASN1)
! 631: i2d_PKCS7_bio_stream(out, p7, in, flags);
! 632: else {
! 633: BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
! 634: goto end;
! 635: }
! 636: }
! 637: ret = 0;
! 638: end:
! 639: if (ret)
! 640: ERR_print_errors(bio_err);
! 641: sk_X509_pop_free(encerts, X509_free);
! 642: sk_X509_pop_free(other, X509_free);
! 643: if (vpm)
! 644: X509_VERIFY_PARAM_free(vpm);
! 645: if (sksigners)
! 646: sk_OPENSSL_STRING_free(sksigners);
! 647: if (skkeys)
! 648: sk_OPENSSL_STRING_free(skkeys);
! 649: X509_STORE_free(store);
! 650: X509_free(cert);
! 651: X509_free(recip);
! 652: X509_free(signer);
! 653: EVP_PKEY_free(key);
! 654: PKCS7_free(p7);
! 655: BIO_free(in);
! 656: BIO_free(indata);
! 657: BIO_free_all(out);
! 658: free(passin);
! 659:
! 660: return (ret);
! 661: }
! 662:
! 663: static int
! 664: save_certs(char *signerfile, STACK_OF(X509) * signers)
! 665: {
! 666: int i;
! 667: BIO *tmp;
! 668: if (!signerfile)
! 669: return 1;
! 670: tmp = BIO_new_file(signerfile, "w");
! 671: if (!tmp)
! 672: return 0;
! 673: for (i = 0; i < sk_X509_num(signers); i++)
! 674: PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
! 675: BIO_free(tmp);
! 676: return 1;
! 677: }
! 678:
! 679:
! 680: /* Minimal callback just to output policy info (if any) */
! 681:
! 682: static int
! 683: smime_cb(int ok, X509_STORE_CTX * ctx)
! 684: {
! 685: int error;
! 686:
! 687: error = X509_STORE_CTX_get_error(ctx);
! 688:
! 689: if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
! 690: && ((error != X509_V_OK) || (ok != 2)))
! 691: return ok;
! 692:
! 693: policies_print(NULL, ctx);
! 694:
! 695: return ok;
! 696:
! 697: }