smime.c 22.1 KB
Newer Older
1
/* smime.c */
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 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    licensing@OpenSSL.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This product includes cryptographic software written by Eric Young
 * (eay@cryptsoft.com).  This product includes software written by Tim
 * Hudson (tjh@cryptsoft.com).
 *
 */

/* S/MIME utility function */

#include <stdio.h>
#include <string.h>
63
#include "apps.h"
64
#include <openssl/crypto.h>
65 66
#include <openssl/pem.h>
#include <openssl/err.h>
67 68
#include <openssl/x509_vfy.h>
#include <openssl/x509v3.h>
69 70 71

#undef PROG
#define PROG smime_main
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 77
#define SMIME_IP	0x20
#define SMIME_SIGNERS	0x40
78
#define SMIME_ENCRYPT	(1 | SMIME_OP)
79 80 81
#define SMIME_DECRYPT	(2 | SMIME_IP)
#define SMIME_SIGN	(3 | SMIME_OP | SMIME_SIGNERS)
#define SMIME_VERIFY	(4 | SMIME_IP)
D
Dr. Stephen Henson 已提交
82
#define SMIME_PK7OUT	(5 | SMIME_IP | SMIME_OP)
83
#define SMIME_RESIGN	(6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
84

85 86
int MAIN(int, char **);

87
int MAIN(int argc, char **argv)
D
Dr. Stephen Henson 已提交
88
	{
89
	ENGINE *e = NULL;
90 91 92
	int operation = 0;
	int ret = 0;
	char **args;
N
Nils Larsch 已提交
93
	const char *inmode = "r", *outmode = "w";
94 95
	char *infile = NULL, *outfile = NULL;
	char *signerfile = NULL, *recipfile = NULL;
B
Ben Laurie 已提交
96
	STACK_OF(STRING) *sksigners = NULL, *skkeys = NULL;
97
	char *certfile = NULL, *keyfile = NULL, *contfile=NULL;
D
 
Dr. Stephen Henson 已提交
98
	const EVP_CIPHER *cipher = NULL;
99 100 101 102 103 104 105
	PKCS7 *p7 = NULL;
	X509_STORE *store = NULL;
	X509 *cert = NULL, *recip = NULL, *signer = NULL;
	EVP_PKEY *key = NULL;
	STACK_OF(X509) *encerts = NULL, *other = NULL;
	BIO *in = NULL, *out = NULL, *indata = NULL;
	int badarg = 0;
106
	int flags = PKCS7_DETACHED;
107
	char *to = NULL, *from = NULL, *subject = NULL;
D
Dr. Stephen Henson 已提交
108 109
	char *CAfile = NULL, *CApath = NULL;
	char *passargin = NULL, *passin = NULL;
110
	char *inrand = NULL;
111
	int need_rand = 0;
112
	int indef = 0;
113
	const EVP_MD *sign_md = NULL;
114
	int informat = FORMAT_SMIME, outformat = FORMAT_SMIME;
R
Richard Levitte 已提交
115
        int keyform = FORMAT_PEM;
116
#ifndef OPENSSL_NO_ENGINE
117
	char *engine=NULL;
118
#endif
119

120 121
	X509_VERIFY_PARAM *vpm = NULL;

122
	args = argv + 1;
123 124
	ret = 1;

D
 
Dr. Stephen Henson 已提交
125 126 127
	apps_startup();

	if (bio_err == NULL)
D
Dr. Stephen Henson 已提交
128
		{
D
 
Dr. Stephen Henson 已提交
129 130
		if ((bio_err = BIO_new(BIO_s_file())) != NULL)
			BIO_set_fp(bio_err, stderr, BIO_NOCLOSE|BIO_FP_TEXT);
D
Dr. Stephen Henson 已提交
131
		}
D
 
Dr. Stephen Henson 已提交
132

D
Dr. Stephen Henson 已提交
133 134 135
	if (!load_config(bio_err, NULL))
		goto end;

D
Dr. Stephen Henson 已提交
136 137 138 139 140 141 142 143
	while (!badarg && *args && *args[0] == '-')
		{
		if (!strcmp (*args, "-encrypt"))
			operation = SMIME_ENCRYPT;
		else if (!strcmp (*args, "-decrypt"))
			operation = SMIME_DECRYPT;
		else if (!strcmp (*args, "-sign"))
			operation = SMIME_SIGN;
144 145
		else if (!strcmp (*args, "-resign"))
			operation = SMIME_RESIGN;
D
Dr. Stephen Henson 已提交
146 147 148 149
		else if (!strcmp (*args, "-verify"))
			operation = SMIME_VERIFY;
		else if (!strcmp (*args, "-pk7out"))
			operation = SMIME_PK7OUT;
150
#ifndef OPENSSL_NO_DES
151 152 153 154
		else if (!strcmp (*args, "-des3")) 
				cipher = EVP_des_ede3_cbc();
		else if (!strcmp (*args, "-des")) 
				cipher = EVP_des_cbc();
B
Bodo Möller 已提交
155
#endif
B
Bodo Möller 已提交
156 157 158 159
#ifndef OPENSSL_NO_SEED
		else if (!strcmp (*args, "-seed")) 
				cipher = EVP_seed_cbc();
#endif
160
#ifndef OPENSSL_NO_RC2
161 162 163 164 165 166
		else if (!strcmp (*args, "-rc2-40")) 
				cipher = EVP_rc2_40_cbc();
		else if (!strcmp (*args, "-rc2-128")) 
				cipher = EVP_rc2_cbc();
		else if (!strcmp (*args, "-rc2-64")) 
				cipher = EVP_rc2_64_cbc();
167 168
#endif
#ifndef OPENSSL_NO_AES
D
 
Dr. Stephen Henson 已提交
169
		else if (!strcmp(*args,"-aes128"))
170
				cipher = EVP_aes_128_cbc();
D
 
Dr. Stephen Henson 已提交
171
		else if (!strcmp(*args,"-aes192"))
172
				cipher = EVP_aes_192_cbc();
D
 
Dr. Stephen Henson 已提交
173
		else if (!strcmp(*args,"-aes256"))
174
				cipher = EVP_aes_256_cbc();
175 176 177 178 179 180 181 182
#endif
#ifndef OPENSSL_NO_CAMELLIA
		else if (!strcmp(*args,"-camellia128"))
				cipher = EVP_camellia_128_cbc();
		else if (!strcmp(*args,"-camellia192"))
				cipher = EVP_camellia_192_cbc();
		else if (!strcmp(*args,"-camellia256"))
				cipher = EVP_camellia_256_cbc();
B
Bodo Möller 已提交
183
#endif
184 185 186 187 188 189 190 191 192 193 194 195 196 197
		else if (!strcmp (*args, "-text")) 
				flags |= PKCS7_TEXT;
		else if (!strcmp (*args, "-nointern")) 
				flags |= PKCS7_NOINTERN;
		else if (!strcmp (*args, "-noverify")) 
				flags |= PKCS7_NOVERIFY;
		else if (!strcmp (*args, "-nochain")) 
				flags |= PKCS7_NOCHAIN;
		else if (!strcmp (*args, "-nocerts")) 
				flags |= PKCS7_NOCERTS;
		else if (!strcmp (*args, "-noattr")) 
				flags |= PKCS7_NOATTR;
		else if (!strcmp (*args, "-nodetach")) 
				flags &= ~PKCS7_DETACHED;
198 199
		else if (!strcmp (*args, "-nosmimecap"))
				flags |= PKCS7_NOSMIMECAP;
200 201
		else if (!strcmp (*args, "-binary"))
				flags |= PKCS7_BINARY;
202 203
		else if (!strcmp (*args, "-nosigs"))
				flags |= PKCS7_NOSIGS;
204 205 206 207 208 209
		else if (!strcmp (*args, "-stream"))
				indef = 1;
		else if (!strcmp (*args, "-indef"))
				indef = 1;
		else if (!strcmp (*args, "-noindef"))
				indef = 0;
210 211 212 213
		else if (!strcmp (*args, "-nooldmime"))
				flags |= PKCS7_NOOLDMIMETYPE;
		else if (!strcmp (*args, "-crlfeol"))
				flags |= PKCS7_CRLFEOL;
D
Dr. Stephen Henson 已提交
214 215
		else if (!strcmp(*args,"-rand"))
			{
D
Dr. Stephen Henson 已提交
216 217 218 219
			if (!args[1])
				goto argerr;
			args++;
			inrand = *args;
220
			need_rand = 1;
D
Dr. Stephen Henson 已提交
221
			}
222
#ifndef OPENSSL_NO_ENGINE
D
Dr. Stephen Henson 已提交
223 224
		else if (!strcmp(*args,"-engine"))
			{
D
Dr. Stephen Henson 已提交
225 226 227
			if (!args[1])
				goto argerr;
			engine = *++args;
D
Dr. Stephen Henson 已提交
228
			}
229
#endif
D
Dr. Stephen Henson 已提交
230 231
		else if (!strcmp(*args,"-passin"))
			{
D
Dr. Stephen Henson 已提交
232 233 234
			if (!args[1])
				goto argerr;
			passargin = *++args;
D
Dr. Stephen Henson 已提交
235 236 237
			}
		else if (!strcmp (*args, "-to"))
			{
D
Dr. Stephen Henson 已提交
238 239 240
			if (!args[1])
				goto argerr;
			to = *++args;
D
Dr. Stephen Henson 已提交
241 242 243
			}
		else if (!strcmp (*args, "-from"))
			{
D
Dr. Stephen Henson 已提交
244 245 246
			if (!args[1])
				goto argerr;
			from = *++args;
D
Dr. Stephen Henson 已提交
247 248 249
			}
		else if (!strcmp (*args, "-subject"))
			{
D
Dr. Stephen Henson 已提交
250 251 252
			if (!args[1])
				goto argerr;
			subject = *++args;
D
Dr. Stephen Henson 已提交
253 254 255
			}
		else if (!strcmp (*args, "-signer"))
			{
D
Dr. Stephen Henson 已提交
256 257
			if (!args[1])
				goto argerr;
258 259 260 261 262
			/* If previous -signer argument add signer to list */

			if (signerfile)
				{
				if (!sksigners)
B
Ben Laurie 已提交
263 264
					sksigners = sk_STRING_new_null();
				sk_STRING_push(sksigners, signerfile);
265 266 267
				if (!keyfile)
					keyfile = signerfile;
				if (!skkeys)
B
Ben Laurie 已提交
268 269
					skkeys = sk_STRING_new_null();
				sk_STRING_push(skkeys, keyfile);
270 271
				keyfile = NULL;
				}
D
Dr. Stephen Henson 已提交
272
			signerfile = *++args;
D
Dr. Stephen Henson 已提交
273 274 275
			}
		else if (!strcmp (*args, "-recip"))
			{
D
Dr. Stephen Henson 已提交
276 277 278
			if (!args[1])
				goto argerr;
			recipfile = *++args;
D
Dr. Stephen Henson 已提交
279
			}
280 281 282 283 284 285 286 287 288 289 290 291
		else if (!strcmp (*args, "-md"))
			{
			if (!args[1])
				goto argerr;
			sign_md = EVP_get_digestbyname(*++args);
			if (sign_md == NULL)
				{
				BIO_printf(bio_err, "Unknown digest %s\n",
							*args);
				goto argerr;
				}
			}
D
Dr. Stephen Henson 已提交
292 293
		else if (!strcmp (*args, "-inkey"))
			{
D
Dr. Stephen Henson 已提交
294 295
			if (!args[1])	
				goto argerr;
296 297 298 299 300 301 302 303 304
			/* If previous -inkey arument add signer to list */
			if (keyfile)
				{
				if (!signerfile)
					{
					BIO_puts(bio_err, "Illegal -inkey without -signer\n");
					goto argerr;
					}
				if (!sksigners)
B
Ben Laurie 已提交
305 306
					sksigners = sk_STRING_new_null();
				sk_STRING_push(sksigners, signerfile);
307 308
				signerfile = NULL;
				if (!skkeys)
B
Ben Laurie 已提交
309 310
					skkeys = sk_STRING_new_null();
				sk_STRING_push(skkeys, keyfile);
311
				}
D
Dr. Stephen Henson 已提交
312 313
			keyfile = *++args;
			}
D
Dr. Stephen Henson 已提交
314 315
		else if (!strcmp (*args, "-keyform"))
			{
D
Dr. Stephen Henson 已提交
316 317 318
			if (!args[1])
				goto argerr;
			keyform = str2fmt(*++args);
D
Dr. Stephen Henson 已提交
319 320 321
			}
		else if (!strcmp (*args, "-certfile"))
			{
D
Dr. Stephen Henson 已提交
322 323 324
			if (!args[1])
				goto argerr;
			certfile = *++args;
D
Dr. Stephen Henson 已提交
325 326 327
			}
		else if (!strcmp (*args, "-CAfile"))
			{
D
Dr. Stephen Henson 已提交
328 329 330
			if (!args[1])
				goto argerr;
			CAfile = *++args;
D
Dr. Stephen Henson 已提交
331 332 333
			}
		else if (!strcmp (*args, "-CApath"))
			{
D
Dr. Stephen Henson 已提交
334 335 336
			if (!args[1])
				goto argerr;
			CApath = *++args;
D
Dr. Stephen Henson 已提交
337 338 339
			}
		else if (!strcmp (*args, "-in"))
			{
D
Dr. Stephen Henson 已提交
340 341 342
			if (!args[1])
				goto argerr;
			infile = *++args;
D
Dr. Stephen Henson 已提交
343 344 345
			}
		else if (!strcmp (*args, "-inform"))
			{
D
Dr. Stephen Henson 已提交
346 347 348
			if (!args[1])
				goto argerr;
			informat = str2fmt(*++args);
D
Dr. Stephen Henson 已提交
349 350 351
			}
		else if (!strcmp (*args, "-outform"))
			{
D
Dr. Stephen Henson 已提交
352 353 354
			if (!args[1])
				goto argerr;
			outformat = str2fmt(*++args);
D
Dr. Stephen Henson 已提交
355 356 357
			}
		else if (!strcmp (*args, "-out"))
			{
D
Dr. Stephen Henson 已提交
358 359 360
			if (!args[1])
				goto argerr;
			outfile = *++args;
D
Dr. Stephen Henson 已提交
361 362 363
			}
		else if (!strcmp (*args, "-content"))
			{
D
Dr. Stephen Henson 已提交
364 365 366
			if (!args[1])
				goto argerr;
			contfile = *++args;
D
Dr. Stephen Henson 已提交
367
			}
D
Dr. Stephen Henson 已提交
368
		else if (args_verify(&args, NULL, &badarg, bio_err, &vpm))
369
			continue;
370
		else if ((cipher = EVP_get_cipherbyname(*args + 1)) == NULL)
371
			badarg = 1;
372
		args++;
D
Dr. Stephen Henson 已提交
373
		}
374

375
	if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners))
376 377 378 379
		{
		BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
		goto argerr;
		}
380

381
	if (operation & SMIME_SIGNERS)
D
Dr. Stephen Henson 已提交
382
		{
383 384 385 386 387 388 389 390 391
		/* Check to see if any final signer needs to be appended */
		if (keyfile && !signerfile)
			{
			BIO_puts(bio_err, "Illegal -inkey without -signer\n");
			goto argerr;
			}
		if (signerfile)
			{
			if (!sksigners)
B
Ben Laurie 已提交
392 393
				sksigners = sk_STRING_new_null();
			sk_STRING_push(sksigners, signerfile);
394
			if (!skkeys)
B
Ben Laurie 已提交
395
				skkeys = sk_STRING_new_null();
396 397
			if (!keyfile)
				keyfile = signerfile;
B
Ben Laurie 已提交
398
			sk_STRING_push(skkeys, keyfile);
399 400
			}
		if (!sksigners)
D
Dr. Stephen Henson 已提交
401
			{
402 403
			BIO_printf(bio_err, "No signer certificate specified\n");
			badarg = 1;
D
Dr. Stephen Henson 已提交
404
			}
405 406
		signerfile = NULL;
		keyfile = NULL;
407
		need_rand = 1;
D
Dr. Stephen Henson 已提交
408 409 410
		}
	else if (operation == SMIME_DECRYPT)
		{
411
		if (!recipfile && !keyfile)
D
Dr. Stephen Henson 已提交
412
			{
413
			BIO_printf(bio_err, "No recipient certificate or key specified\n");
414
			badarg = 1;
D
Dr. Stephen Henson 已提交
415
			}
416
		}
D
Dr. Stephen Henson 已提交
417 418 419 420
	else if (operation == SMIME_ENCRYPT)
		{
		if (!*args)
			{
421 422
			BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
			badarg = 1;
D
Dr. Stephen Henson 已提交
423
			}
424
		need_rand = 1;
D
Dr. Stephen Henson 已提交
425 426 427
		}
	else if (!operation)
		badarg = 1;
428

D
Dr. Stephen Henson 已提交
429 430
	if (badarg)
		{
D
Dr. Stephen Henson 已提交
431
		argerr:
432 433 434 435 436 437 438
		BIO_printf (bio_err, "Usage smime [options] cert.pem ...\n");
		BIO_printf (bio_err, "where options are\n");
		BIO_printf (bio_err, "-encrypt       encrypt message\n");
		BIO_printf (bio_err, "-decrypt       decrypt encrypted message\n");
		BIO_printf (bio_err, "-sign          sign message\n");
		BIO_printf (bio_err, "-verify        verify signed message\n");
		BIO_printf (bio_err, "-pk7out        output PKCS#7 structure\n");
439
#ifndef OPENSSL_NO_DES
440
		BIO_printf (bio_err, "-des3          encrypt with triple DES\n");
B
Bodo Möller 已提交
441 442
		BIO_printf (bio_err, "-des           encrypt with DES\n");
#endif
B
Bodo Möller 已提交
443 444 445
#ifndef OPENSSL_NO_SEED
		BIO_printf (bio_err, "-seed          encrypt with SEED\n");
#endif
446
#ifndef OPENSSL_NO_RC2
B
Bodo Möller 已提交
447
		BIO_printf (bio_err, "-rc2-40        encrypt with RC2-40 (default)\n");
448 449
		BIO_printf (bio_err, "-rc2-64        encrypt with RC2-64\n");
		BIO_printf (bio_err, "-rc2-128       encrypt with RC2-128\n");
450 451 452 453
#endif
#ifndef OPENSSL_NO_AES
		BIO_printf (bio_err, "-aes128, -aes192, -aes256\n");
		BIO_printf (bio_err, "               encrypt PEM output with cbc aes\n");
454 455 456 457
#endif
#ifndef OPENSSL_NO_CAMELLIA
		BIO_printf (bio_err, "-camellia128, -camellia192, -camellia256\n");
		BIO_printf (bio_err, "               encrypt PEM output with cbc camellia\n");
B
Bodo Möller 已提交
458
#endif
459 460 461 462 463 464 465
		BIO_printf (bio_err, "-nointern      don't search certificates in message for signer\n");
		BIO_printf (bio_err, "-nosigs        don't verify message signature\n");
		BIO_printf (bio_err, "-noverify      don't verify signers certificate\n");
		BIO_printf (bio_err, "-nocerts       don't include signers certificate when signing\n");
		BIO_printf (bio_err, "-nodetach      use opaque signing\n");
		BIO_printf (bio_err, "-noattr        don't include any signed attributes\n");
		BIO_printf (bio_err, "-binary        don't translate message to text\n");
466 467
		BIO_printf (bio_err, "-certfile file other certificates file\n");
		BIO_printf (bio_err, "-signer file   signer certificate file\n");
B
Bodo Möller 已提交
468
		BIO_printf (bio_err, "-recip  file   recipient certificate file for decryption\n");
469
		BIO_printf (bio_err, "-in file       input file\n");
D
 
Dr. Stephen Henson 已提交
470
		BIO_printf (bio_err, "-inform arg    input format SMIME (default), PEM or DER\n");
471
		BIO_printf (bio_err, "-inkey file    input private key (if not signer or recipient)\n");
R
Richard Levitte 已提交
472
		BIO_printf (bio_err, "-keyform arg   input private key format (PEM or ENGINE)\n");
473
		BIO_printf (bio_err, "-out file      output file\n");
D
 
Dr. Stephen Henson 已提交
474 475
		BIO_printf (bio_err, "-outform arg   output format SMIME (default), PEM or DER\n");
		BIO_printf (bio_err, "-content file  supply or override content for detached signature\n");
476 477 478 479
		BIO_printf (bio_err, "-to addr       to address\n");
		BIO_printf (bio_err, "-from ad       from address\n");
		BIO_printf (bio_err, "-subject s     subject\n");
		BIO_printf (bio_err, "-text          include or delete text MIME headers\n");
480 481
		BIO_printf (bio_err, "-CApath dir    trusted certificates directory\n");
		BIO_printf (bio_err, "-CAfile file   trusted certificates file\n");
482 483
		BIO_printf (bio_err, "-crl_check     check revocation status of signer's certificate using CRLs\n");
		BIO_printf (bio_err, "-crl_check_all check revocation status of signer's certificate chain using CRLs\n");
484
#ifndef OPENSSL_NO_ENGINE
485
		BIO_printf (bio_err, "-engine e      use engine e, possibly a hardware device.\n");
486
#endif
487
		BIO_printf (bio_err, "-passin arg    input file pass phrase source\n");
B
Bodo Möller 已提交
488
		BIO_printf(bio_err,  "-rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR);
489 490
		BIO_printf(bio_err,  "               load the file (or the files in the directory) into\n");
		BIO_printf(bio_err,  "               the random number generator\n");
B
Bodo Möller 已提交
491
		BIO_printf (bio_err, "cert.pem       recipient certificate(s) for encryption\n");
492
		goto end;
D
Dr. Stephen Henson 已提交
493
		}
494

495
#ifndef OPENSSL_NO_ENGINE
496
        e = setup_engine(bio_err, engine, 0);
497
#endif
498

D
Dr. Stephen Henson 已提交
499 500
	if (!app_passwd(bio_err, passargin, NULL, &passin, NULL))
		{
D
Dr. Stephen Henson 已提交
501 502
		BIO_printf(bio_err, "Error getting password\n");
		goto end;
D
Dr. Stephen Henson 已提交
503
		}
D
Dr. Stephen Henson 已提交
504

D
Dr. Stephen Henson 已提交
505 506
	if (need_rand)
		{
507
		app_RAND_load_file(NULL, bio_err, (inrand != NULL));
508 509 510
		if (inrand != NULL)
			BIO_printf(bio_err,"%ld semi-random bytes loaded\n",
				app_RAND_load_files(inrand));
D
Dr. Stephen Henson 已提交
511
		}
512

513 514
	ret = 2;

515
	if (!(operation & SMIME_SIGNERS))
D
Dr. Stephen Henson 已提交
516
		flags &= ~PKCS7_DETACHED;
517

D
Dr. Stephen Henson 已提交
518 519 520 521 522 523 524 525 526
	if (operation & SMIME_OP)
		{
		if (outformat == FORMAT_ASN1)
			outmode = "wb";
		}
	else
		{
		if (flags & PKCS7_BINARY)
			outmode = "wb";
527 528 529 530
		}

	if (operation & SMIME_IP)
		{
D
Dr. Stephen Henson 已提交
531 532 533
		if (informat == FORMAT_ASN1)
			inmode = "rb";
		}
534 535 536 537 538
	else
		{
		if (flags & PKCS7_BINARY)
			inmode = "rb";
		}
539

D
Dr. Stephen Henson 已提交
540 541 542 543
	if (operation == SMIME_ENCRYPT)
		{
		if (!cipher)
			{
544
#ifndef OPENSSL_NO_RC2			
B
Bodo Möller 已提交
545 546 547 548 549
			cipher = EVP_rc2_40_cbc();
#else
			BIO_printf(bio_err, "No cipher selected\n");
			goto end;
#endif
D
Dr. Stephen Henson 已提交
550
			}
551
		encerts = sk_X509_new_null();
D
Dr. Stephen Henson 已提交
552 553 554 555 556
		while (*args)
			{
			if (!(cert = load_cert(bio_err,*args,FORMAT_PEM,
				NULL, e, "recipient certificate file")))
				{
557
#if 0				/* An appropriate message is already printed */
U
Ulf Möller 已提交
558
				BIO_printf(bio_err, "Can't read recipient certificate file %s\n", *args);
559
#endif
560
				goto end;
D
Dr. Stephen Henson 已提交
561
				}
562
			sk_X509_push(encerts, cert);
563 564
			cert = NULL;
			args++;
D
Dr. Stephen Henson 已提交
565
			}
566 567
		}

D
Dr. Stephen Henson 已提交
568 569 570 571 572
	if (certfile)
		{
		if (!(other = load_certs(bio_err,certfile,FORMAT_PEM, NULL,
			e, "certificate file")))
			{
573 574
			ERR_print_errors(bio_err);
			goto end;
D
Dr. Stephen Henson 已提交
575
			}
576 577
		}

D
Dr. Stephen Henson 已提交
578 579 580 581 582
	if (recipfile && (operation == SMIME_DECRYPT))
		{
		if (!(recip = load_cert(bio_err,recipfile,FORMAT_PEM,NULL,
			e, "recipient certificate file")))
			{
583 584
			ERR_print_errors(bio_err);
			goto end;
D
Dr. Stephen Henson 已提交
585
			}
586 587
		}

D
Dr. Stephen Henson 已提交
588 589 590 591 592 593 594 595 596 597 598
	if (operation == SMIME_DECRYPT)
		{
		if (!keyfile)
			keyfile = recipfile;
		}
	else if (operation == SMIME_SIGN)
		{
		if (!keyfile)
			keyfile = signerfile;
		}
	else keyfile = NULL;
599

D
Dr. Stephen Henson 已提交
600 601
	if (keyfile)
		{
602
		key = load_key(bio_err, keyfile, keyform, 0, passin, e,
603
			       "signing key file");
D
Dr. Stephen Henson 已提交
604
		if (!key)
605
			goto end;
D
Dr. Stephen Henson 已提交
606
		}
607

D
Dr. Stephen Henson 已提交
608 609 610 611
	if (infile)
		{
		if (!(in = BIO_new_file(infile, inmode)))
			{
612 613 614
			BIO_printf (bio_err,
				 "Can't open input file %s\n", infile);
			goto end;
D
Dr. Stephen Henson 已提交
615
			}
616
		}
D
Dr. Stephen Henson 已提交
617 618
	else
		in = BIO_new_fp(stdin, BIO_NOCLOSE);
619

620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
	if (operation & SMIME_IP)
		{
		if (informat == FORMAT_SMIME) 
			p7 = SMIME_read_PKCS7(in, &indata);
		else if (informat == FORMAT_PEM) 
			p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
		else if (informat == FORMAT_ASN1) 
			p7 = d2i_PKCS7_bio(in, NULL);
		else
			{
			BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
			goto end;
			}

		if (!p7)
			{
			BIO_printf(bio_err, "Error reading S/MIME message\n");
			goto end;
			}
		if (contfile)
			{
			BIO_free(indata);
			if (!(indata = BIO_new_file(contfile, "rb")))
				{
				BIO_printf(bio_err, "Can't read content file %s\n", contfile);
				goto end;
				}
			}
		}

D
Dr. Stephen Henson 已提交
650 651 652 653
	if (outfile)
		{
		if (!(out = BIO_new_file(outfile, outmode)))
			{
654 655 656
			BIO_printf (bio_err,
				 "Can't open output file %s\n", outfile);
			goto end;
D
Dr. Stephen Henson 已提交
657
			}
658
		}
D
Dr. Stephen Henson 已提交
659 660
	else
		{
661
		out = BIO_new_fp(stdout, BIO_NOCLOSE);
662
#ifdef OPENSSL_SYS_VMS
663 664 665 666 667
		{
		    BIO *tmpbio = BIO_new(BIO_f_linebuffer());
		    out = BIO_push(tmpbio, out);
		}
#endif
D
Dr. Stephen Henson 已提交
668
		}
669

D
Dr. Stephen Henson 已提交
670 671 672 673
	if (operation == SMIME_VERIFY)
		{
		if (!(store = setup_verify(bio_err, CAfile, CApath)))
			goto end;
674 675 676
		X509_STORE_set_verify_cb_func(store, smime_cb);
		if (vpm)
			X509_STORE_set1_param(store, vpm);
D
Dr. Stephen Henson 已提交
677
		}
678

679

680
	ret = 3;
681

D
Dr. Stephen Henson 已提交
682
	if (operation == SMIME_ENCRYPT)
683 684 685
		{
		if (indef)
			flags |= PKCS7_STREAM;
686
		p7 = PKCS7_encrypt(encerts, in, cipher, flags);
687
		}
688
	else if (operation & SMIME_SIGNERS)
D
Dr. Stephen Henson 已提交
689
		{
690
		int i;
691 692
		/* If detached data content we only enable streaming if
		 * S/MIME output format.
693
		 */
694 695
		if (operation == SMIME_SIGN)
			{
696 697 698 699 700 701
			if (flags & PKCS7_DETACHED)
				{
				if (outformat == FORMAT_SMIME)
					flags |= PKCS7_STREAM;
				}
			else if (indef)
702 703 704
				flags |= PKCS7_STREAM;
			flags |= PKCS7_PARTIAL;
			p7 = PKCS7_sign(NULL, NULL, other, in, flags);
705 706
			if (!p7)
				goto end;
707 708 709
			}
		else
			flags |= PKCS7_REUSE_DIGEST;
B
Ben Laurie 已提交
710
		for (i = 0; i < sk_STRING_num(sksigners); i++)
711
			{
B
Ben Laurie 已提交
712 713
			signerfile = sk_STRING_value(sksigners, i);
			keyfile = sk_STRING_value(skkeys, i);
714 715 716 717 718 719 720 721 722
			signer = load_cert(bio_err, signerfile,FORMAT_PEM, NULL,
					e, "signer certificate");
			if (!signer)
				goto end;
			key = load_key(bio_err, keyfile, keyform, 0, passin, e,
			       "signing key file");
			if (!key)
				goto end;
			if (!PKCS7_sign_add_signer(p7, signer, key,
723
						sign_md, flags))
724 725 726 727 728 729
				goto end;
			X509_free(signer);
			signer = NULL;
			EVP_PKEY_free(key);
			key = NULL;
			}
730 731
		/* If not streaming or resigning finalize structure */
		if ((operation == SMIME_SIGN) && !(flags & PKCS7_STREAM))
D
Dr. Stephen Henson 已提交
732
			{
733 734
			if (!PKCS7_final(p7, in, flags))
				goto end;
D
Dr. Stephen Henson 已提交
735
			}
736
		}
737

D
Dr. Stephen Henson 已提交
738 739
	if (!p7)
		{
740 741
		BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
		goto end;
D
Dr. Stephen Henson 已提交
742
		}
743

744
	ret = 4;
D
Dr. Stephen Henson 已提交
745 746 747 748
	if (operation == SMIME_DECRYPT)
		{
		if (!PKCS7_decrypt(p7, key, recip, out, flags))
			{
749
			BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n");
750
			goto end;
D
Dr. Stephen Henson 已提交
751
			}
752
		}
D
Dr. Stephen Henson 已提交
753 754
	else if (operation == SMIME_VERIFY)
		{
755
		STACK_OF(X509) *signers;
D
Dr. Stephen Henson 已提交
756
		if (PKCS7_verify(p7, other, store, indata, out, flags))
B
Bodo Möller 已提交
757
			BIO_printf(bio_err, "Verification successful\n");
D
Dr. Stephen Henson 已提交
758 759
		else
			{
B
Bodo Möller 已提交
760
			BIO_printf(bio_err, "Verification failure\n");
761
			goto end;
D
Dr. Stephen Henson 已提交
762
			}
763
		signers = PKCS7_get0_signers(p7, other, flags);
D
Dr. Stephen Henson 已提交
764 765
		if (!save_certs(signerfile, signers))
			{
766 767
			BIO_printf(bio_err, "Error writing signers to %s\n",
								signerfile);
768 769
			ret = 5;
			goto end;
D
Dr. Stephen Henson 已提交
770
			}
771
		sk_X509_free(signers);
D
Dr. Stephen Henson 已提交
772 773
		}
	else if (operation == SMIME_PK7OUT)
774
		PEM_write_bio_PKCS7(out, p7);
D
Dr. Stephen Henson 已提交
775 776 777 778 779 780 781 782 783
	else
		{
		if (to)
			BIO_printf(out, "To: %s\n", to);
		if (from)
			BIO_printf(out, "From: %s\n", from);
		if (subject)
			BIO_printf(out, "Subject: %s\n", subject);
		if (outformat == FORMAT_SMIME) 
784 785 786 787 788 789
			{
			if (operation == SMIME_RESIGN)
				SMIME_write_PKCS7(out, p7, indata, flags);
			else
				SMIME_write_PKCS7(out, p7, in, flags);
			}
D
Dr. Stephen Henson 已提交
790
		else if (outformat == FORMAT_PEM) 
791
			PEM_write_bio_PKCS7_stream(out, p7, in, flags);
D
Dr. Stephen Henson 已提交
792
		else if (outformat == FORMAT_ASN1) 
793
			i2d_PKCS7_bio_stream(out,p7, in, flags);
D
Dr. Stephen Henson 已提交
794 795
		else
			{
796 797
			BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
			goto end;
D
Dr. Stephen Henson 已提交
798
			}
799
		}
800
	ret = 0;
801
end:
802 803
	if (need_rand)
		app_RAND_write_file(NULL, bio_err);
D
Dr. Stephen Henson 已提交
804
	if (ret) ERR_print_errors(bio_err);
805 806
	sk_X509_pop_free(encerts, X509_free);
	sk_X509_pop_free(other, X509_free);
807 808
	if (vpm)
		X509_VERIFY_PARAM_free(vpm);
809
	if (sksigners)
B
Ben Laurie 已提交
810
		sk_STRING_free(sksigners);
811
	if (skkeys)
B
Ben Laurie 已提交
812
		sk_STRING_free(skkeys);
813 814 815 816 817 818 819 820
	X509_STORE_free(store);
	X509_free(cert);
	X509_free(recip);
	X509_free(signer);
	EVP_PKEY_free(key);
	PKCS7_free(p7);
	BIO_free(in);
	BIO_free(indata);
821
	BIO_free_all(out);
D
Dr. Stephen Henson 已提交
822
	if (passin) OPENSSL_free(passin);
823 824 825
	return (ret);
}

B
Bodo Möller 已提交
826
static int save_certs(char *signerfile, STACK_OF(X509) *signers)
D
Dr. Stephen Henson 已提交
827
	{
828 829
	int i;
	BIO *tmp;
D
Dr. Stephen Henson 已提交
830 831
	if (!signerfile)
		return 1;
832
	tmp = BIO_new_file(signerfile, "w");
D
Dr. Stephen Henson 已提交
833
	if (!tmp) return 0;
834 835 836 837
	for(i = 0; i < sk_X509_num(signers); i++)
		PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
	BIO_free(tmp);
	return 1;
D
Dr. Stephen Henson 已提交
838
	}
839
	
840 841 842 843 844 845 846 847 848 849 850 851 852

/* Minimal callback just to output policy info (if any) */

static int smime_cb(int ok, X509_STORE_CTX *ctx)
	{
	int error;

	error = X509_STORE_CTX_get_error(ctx);

	if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
		&& ((error != X509_V_OK) || (ok != 2)))
		return ok;

D
Dr. Stephen Henson 已提交
853
	policies_print(NULL, ctx);
854 855 856 857

	return ok;

	}