159191Skris/* smime.c */
2194206Ssimon/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3160814Ssimon * project.
459191Skris */
559191Skris/* ====================================================================
6160814Ssimon * Copyright (c) 1999-2004 The OpenSSL Project.  All rights reserved.
759191Skris *
859191Skris * Redistribution and use in source and binary forms, with or without
959191Skris * modification, are permitted provided that the following conditions
1059191Skris * are met:
1159191Skris *
1259191Skris * 1. Redistributions of source code must retain the above copyright
1359191Skris *    notice, this list of conditions and the following disclaimer.
1459191Skris *
1559191Skris * 2. Redistributions in binary form must reproduce the above copyright
1659191Skris *    notice, this list of conditions and the following disclaimer in
1759191Skris *    the documentation and/or other materials provided with the
1859191Skris *    distribution.
1959191Skris *
2059191Skris * 3. All advertising materials mentioning features or use of this
2159191Skris *    software must display the following acknowledgment:
2259191Skris *    "This product includes software developed by the OpenSSL Project
2359191Skris *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2459191Skris *
2559191Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2659191Skris *    endorse or promote products derived from this software without
2759191Skris *    prior written permission. For written permission, please contact
2859191Skris *    licensing@OpenSSL.org.
2959191Skris *
3059191Skris * 5. Products derived from this software may not be called "OpenSSL"
3159191Skris *    nor may "OpenSSL" appear in their names without prior written
3259191Skris *    permission of the OpenSSL Project.
3359191Skris *
3459191Skris * 6. Redistributions of any form whatsoever must retain the following
3559191Skris *    acknowledgment:
3659191Skris *    "This product includes software developed by the OpenSSL Project
3759191Skris *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3859191Skris *
3959191Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
4059191Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4159191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4259191Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4359191Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4459191Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4559191Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4659191Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4759191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4859191Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
4959191Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
5059191Skris * OF THE POSSIBILITY OF SUCH DAMAGE.
5159191Skris * ====================================================================
5259191Skris *
5359191Skris * This product includes cryptographic software written by Eric Young
5459191Skris * (eay@cryptsoft.com).  This product includes software written by Tim
5559191Skris * Hudson (tjh@cryptsoft.com).
5659191Skris *
5759191Skris */
5859191Skris
5959191Skris/* S/MIME utility function */
6059191Skris
6159191Skris#include <stdio.h>
6259191Skris#include <string.h>
6359191Skris#include "apps.h"
6459191Skris#include <openssl/crypto.h>
6559191Skris#include <openssl/pem.h>
6659191Skris#include <openssl/err.h>
67160814Ssimon#include <openssl/x509_vfy.h>
68160814Ssimon#include <openssl/x509v3.h>
6959191Skris
7059191Skris#undef PROG
7159191Skris#define PROG smime_main
7259191Skrisstatic int save_certs(char *signerfile, STACK_OF(X509) *signers);
73160814Ssimonstatic int smime_cb(int ok, X509_STORE_CTX *ctx);
7459191Skris
7559191Skris#define SMIME_OP	0x10
76238405Sjkim#define SMIME_IP	0x20
77238405Sjkim#define SMIME_SIGNERS	0x40
7859191Skris#define SMIME_ENCRYPT	(1 | SMIME_OP)
79238405Sjkim#define SMIME_DECRYPT	(2 | SMIME_IP)
80238405Sjkim#define SMIME_SIGN	(3 | SMIME_OP | SMIME_SIGNERS)
81238405Sjkim#define SMIME_VERIFY	(4 | SMIME_IP)
82238405Sjkim#define SMIME_PK7OUT	(5 | SMIME_IP | SMIME_OP)
83238405Sjkim#define SMIME_RESIGN	(6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
8459191Skris
8559191Skrisint MAIN(int, char **);
8659191Skris
8759191Skrisint MAIN(int argc, char **argv)
88160814Ssimon	{
89109998Smarkm	ENGINE *e = NULL;
9059191Skris	int operation = 0;
9159191Skris	int ret = 0;
9259191Skris	char **args;
93160814Ssimon	const char *inmode = "r", *outmode = "w";
9459191Skris	char *infile = NULL, *outfile = NULL;
9559191Skris	char *signerfile = NULL, *recipfile = NULL;
96238405Sjkim	STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL;
9768651Skris	char *certfile = NULL, *keyfile = NULL, *contfile=NULL;
98109998Smarkm	const EVP_CIPHER *cipher = NULL;
9959191Skris	PKCS7 *p7 = NULL;
10059191Skris	X509_STORE *store = NULL;
10159191Skris	X509 *cert = NULL, *recip = NULL, *signer = NULL;
10259191Skris	EVP_PKEY *key = NULL;
10359191Skris	STACK_OF(X509) *encerts = NULL, *other = NULL;
10459191Skris	BIO *in = NULL, *out = NULL, *indata = NULL;
10559191Skris	int badarg = 0;
106160814Ssimon	int flags = PKCS7_DETACHED;
10759191Skris	char *to = NULL, *from = NULL, *subject = NULL;
10859191Skris	char *CAfile = NULL, *CApath = NULL;
10959191Skris	char *passargin = NULL, *passin = NULL;
11059191Skris	char *inrand = NULL;
11159191Skris	int need_rand = 0;
112238405Sjkim	int indef = 0;
113238405Sjkim	const EVP_MD *sign_md = NULL;
11468651Skris	int informat = FORMAT_SMIME, outformat = FORMAT_SMIME;
115109998Smarkm        int keyform = FORMAT_PEM;
116111147Snectar#ifndef OPENSSL_NO_ENGINE
117109998Smarkm	char *engine=NULL;
118111147Snectar#endif
119109998Smarkm
120160814Ssimon	X509_VERIFY_PARAM *vpm = NULL;
121160814Ssimon
12259191Skris	args = argv + 1;
12359191Skris	ret = 1;
12459191Skris
125109998Smarkm	apps_startup();
126109998Smarkm
127109998Smarkm	if (bio_err == NULL)
128160814Ssimon		{
129109998Smarkm		if ((bio_err = BIO_new(BIO_s_file())) != NULL)
130109998Smarkm			BIO_set_fp(bio_err, stderr, BIO_NOCLOSE|BIO_FP_TEXT);
131160814Ssimon		}
132109998Smarkm
133109998Smarkm	if (!load_config(bio_err, NULL))
134109998Smarkm		goto end;
135109998Smarkm
136160814Ssimon	while (!badarg && *args && *args[0] == '-')
137160814Ssimon		{
138160814Ssimon		if (!strcmp (*args, "-encrypt"))
139160814Ssimon			operation = SMIME_ENCRYPT;
140160814Ssimon		else if (!strcmp (*args, "-decrypt"))
141160814Ssimon			operation = SMIME_DECRYPT;
142160814Ssimon		else if (!strcmp (*args, "-sign"))
143160814Ssimon			operation = SMIME_SIGN;
144238405Sjkim		else if (!strcmp (*args, "-resign"))
145238405Sjkim			operation = SMIME_RESIGN;
146160814Ssimon		else if (!strcmp (*args, "-verify"))
147160814Ssimon			operation = SMIME_VERIFY;
148160814Ssimon		else if (!strcmp (*args, "-pk7out"))
149160814Ssimon			operation = SMIME_PK7OUT;
150109998Smarkm#ifndef OPENSSL_NO_DES
15159191Skris		else if (!strcmp (*args, "-des3"))
15259191Skris				cipher = EVP_des_ede3_cbc();
15359191Skris		else if (!strcmp (*args, "-des"))
15459191Skris				cipher = EVP_des_cbc();
15559191Skris#endif
156194206Ssimon#ifndef OPENSSL_NO_SEED
157194206Ssimon		else if (!strcmp (*args, "-seed"))
158194206Ssimon				cipher = EVP_seed_cbc();
159194206Ssimon#endif
160109998Smarkm#ifndef OPENSSL_NO_RC2
16159191Skris		else if (!strcmp (*args, "-rc2-40"))
16259191Skris				cipher = EVP_rc2_40_cbc();
16359191Skris		else if (!strcmp (*args, "-rc2-128"))
16459191Skris				cipher = EVP_rc2_cbc();
16559191Skris		else if (!strcmp (*args, "-rc2-64"))
16659191Skris				cipher = EVP_rc2_64_cbc();
16759191Skris#endif
168109998Smarkm#ifndef OPENSSL_NO_AES
169109998Smarkm		else if (!strcmp(*args,"-aes128"))
170109998Smarkm				cipher = EVP_aes_128_cbc();
171109998Smarkm		else if (!strcmp(*args,"-aes192"))
172109998Smarkm				cipher = EVP_aes_192_cbc();
173109998Smarkm		else if (!strcmp(*args,"-aes256"))
174109998Smarkm				cipher = EVP_aes_256_cbc();
175109998Smarkm#endif
176162911Ssimon#ifndef OPENSSL_NO_CAMELLIA
177162911Ssimon		else if (!strcmp(*args,"-camellia128"))
178162911Ssimon				cipher = EVP_camellia_128_cbc();
179162911Ssimon		else if (!strcmp(*args,"-camellia192"))
180162911Ssimon				cipher = EVP_camellia_192_cbc();
181162911Ssimon		else if (!strcmp(*args,"-camellia256"))
182162911Ssimon				cipher = EVP_camellia_256_cbc();
183162911Ssimon#endif
18459191Skris		else if (!strcmp (*args, "-text"))
18559191Skris				flags |= PKCS7_TEXT;
18659191Skris		else if (!strcmp (*args, "-nointern"))
18759191Skris				flags |= PKCS7_NOINTERN;
18859191Skris		else if (!strcmp (*args, "-noverify"))
18959191Skris				flags |= PKCS7_NOVERIFY;
19059191Skris		else if (!strcmp (*args, "-nochain"))
19159191Skris				flags |= PKCS7_NOCHAIN;
19259191Skris		else if (!strcmp (*args, "-nocerts"))
19359191Skris				flags |= PKCS7_NOCERTS;
19459191Skris		else if (!strcmp (*args, "-noattr"))
19559191Skris				flags |= PKCS7_NOATTR;
19659191Skris		else if (!strcmp (*args, "-nodetach"))
19759191Skris				flags &= ~PKCS7_DETACHED;
19868651Skris		else if (!strcmp (*args, "-nosmimecap"))
19968651Skris				flags |= PKCS7_NOSMIMECAP;
20059191Skris		else if (!strcmp (*args, "-binary"))
20159191Skris				flags |= PKCS7_BINARY;
20259191Skris		else if (!strcmp (*args, "-nosigs"))
20359191Skris				flags |= PKCS7_NOSIGS;
204238405Sjkim		else if (!strcmp (*args, "-stream"))
205238405Sjkim				indef = 1;
206238405Sjkim		else if (!strcmp (*args, "-indef"))
207238405Sjkim				indef = 1;
208238405Sjkim		else if (!strcmp (*args, "-noindef"))
209238405Sjkim				indef = 0;
210120631Snectar		else if (!strcmp (*args, "-nooldmime"))
211120631Snectar				flags |= PKCS7_NOOLDMIMETYPE;
212120631Snectar		else if (!strcmp (*args, "-crlfeol"))
213120631Snectar				flags |= PKCS7_CRLFEOL;
214160814Ssimon		else if (!strcmp(*args,"-rand"))
215160814Ssimon			{
216238405Sjkim			if (!args[1])
217238405Sjkim				goto argerr;
218238405Sjkim			args++;
219238405Sjkim			inrand = *args;
22059191Skris			need_rand = 1;
221160814Ssimon			}
222111147Snectar#ifndef OPENSSL_NO_ENGINE
223160814Ssimon		else if (!strcmp(*args,"-engine"))
224160814Ssimon			{
225238405Sjkim			if (!args[1])
226238405Sjkim				goto argerr;
227238405Sjkim			engine = *++args;
228160814Ssimon			}
229111147Snectar#endif
230160814Ssimon		else if (!strcmp(*args,"-passin"))
231160814Ssimon			{
232238405Sjkim			if (!args[1])
233238405Sjkim				goto argerr;
234238405Sjkim			passargin = *++args;
235160814Ssimon			}
236160814Ssimon		else if (!strcmp (*args, "-to"))
237160814Ssimon			{
238238405Sjkim			if (!args[1])
239238405Sjkim				goto argerr;
240238405Sjkim			to = *++args;
241160814Ssimon			}
242160814Ssimon		else if (!strcmp (*args, "-from"))
243160814Ssimon			{
244238405Sjkim			if (!args[1])
245238405Sjkim				goto argerr;
246238405Sjkim			from = *++args;
247160814Ssimon			}
248160814Ssimon		else if (!strcmp (*args, "-subject"))
249160814Ssimon			{
250238405Sjkim			if (!args[1])
251238405Sjkim				goto argerr;
252238405Sjkim			subject = *++args;
253160814Ssimon			}
254160814Ssimon		else if (!strcmp (*args, "-signer"))
255160814Ssimon			{
256238405Sjkim			if (!args[1])
257238405Sjkim				goto argerr;
258238405Sjkim			/* If previous -signer argument add signer to list */
259238405Sjkim
260238405Sjkim			if (signerfile)
261160814Ssimon				{
262238405Sjkim				if (!sksigners)
263238405Sjkim					sksigners = sk_OPENSSL_STRING_new_null();
264238405Sjkim				sk_OPENSSL_STRING_push(sksigners, signerfile);
265238405Sjkim				if (!keyfile)
266238405Sjkim					keyfile = signerfile;
267238405Sjkim				if (!skkeys)
268238405Sjkim					skkeys = sk_OPENSSL_STRING_new_null();
269238405Sjkim				sk_OPENSSL_STRING_push(skkeys, keyfile);
270238405Sjkim				keyfile = NULL;
271160814Ssimon				}
272238405Sjkim			signerfile = *++args;
273160814Ssimon			}
274160814Ssimon		else if (!strcmp (*args, "-recip"))
275160814Ssimon			{
276238405Sjkim			if (!args[1])
277238405Sjkim				goto argerr;
278238405Sjkim			recipfile = *++args;
279238405Sjkim			}
280238405Sjkim		else if (!strcmp (*args, "-md"))
281238405Sjkim			{
282238405Sjkim			if (!args[1])
283238405Sjkim				goto argerr;
284238405Sjkim			sign_md = EVP_get_digestbyname(*++args);
285238405Sjkim			if (sign_md == NULL)
286160814Ssimon				{
287238405Sjkim				BIO_printf(bio_err, "Unknown digest %s\n",
288238405Sjkim							*args);
289238405Sjkim				goto argerr;
290160814Ssimon				}
291160814Ssimon			}
292160814Ssimon		else if (!strcmp (*args, "-inkey"))
293160814Ssimon			{
294238405Sjkim			if (!args[1])
295238405Sjkim				goto argerr;
296238405Sjkim			/* If previous -inkey arument add signer to list */
297238405Sjkim			if (keyfile)
298160814Ssimon				{
299238405Sjkim				if (!signerfile)
300238405Sjkim					{
301238405Sjkim					BIO_puts(bio_err, "Illegal -inkey without -signer\n");
302238405Sjkim					goto argerr;
303238405Sjkim					}
304238405Sjkim				if (!sksigners)
305238405Sjkim					sksigners = sk_OPENSSL_STRING_new_null();
306238405Sjkim				sk_OPENSSL_STRING_push(sksigners, signerfile);
307238405Sjkim				signerfile = NULL;
308238405Sjkim				if (!skkeys)
309238405Sjkim					skkeys = sk_OPENSSL_STRING_new_null();
310238405Sjkim				sk_OPENSSL_STRING_push(skkeys, keyfile);
311160814Ssimon				}
312238405Sjkim			keyfile = *++args;
313238405Sjkim			}
314160814Ssimon		else if (!strcmp (*args, "-keyform"))
315160814Ssimon			{
316238405Sjkim			if (!args[1])
317238405Sjkim				goto argerr;
318238405Sjkim			keyform = str2fmt(*++args);
319160814Ssimon			}
320160814Ssimon		else if (!strcmp (*args, "-certfile"))
321160814Ssimon			{
322238405Sjkim			if (!args[1])
323238405Sjkim				goto argerr;
324238405Sjkim			certfile = *++args;
325160814Ssimon			}
326160814Ssimon		else if (!strcmp (*args, "-CAfile"))
327160814Ssimon			{
328238405Sjkim			if (!args[1])
329238405Sjkim				goto argerr;
330238405Sjkim			CAfile = *++args;
331160814Ssimon			}
332160814Ssimon		else if (!strcmp (*args, "-CApath"))
333160814Ssimon			{
334238405Sjkim			if (!args[1])
335238405Sjkim				goto argerr;
336238405Sjkim			CApath = *++args;
337160814Ssimon			}
338160814Ssimon		else if (!strcmp (*args, "-in"))
339160814Ssimon			{
340238405Sjkim			if (!args[1])
341238405Sjkim				goto argerr;
342238405Sjkim			infile = *++args;
343160814Ssimon			}
344160814Ssimon		else if (!strcmp (*args, "-inform"))
345160814Ssimon			{
346238405Sjkim			if (!args[1])
347238405Sjkim				goto argerr;
348238405Sjkim			informat = str2fmt(*++args);
349160814Ssimon			}
350160814Ssimon		else if (!strcmp (*args, "-outform"))
351160814Ssimon			{
352238405Sjkim			if (!args[1])
353238405Sjkim				goto argerr;
354238405Sjkim			outformat = str2fmt(*++args);
355160814Ssimon			}
356160814Ssimon		else if (!strcmp (*args, "-out"))
357160814Ssimon			{
358238405Sjkim			if (!args[1])
359238405Sjkim				goto argerr;
360238405Sjkim			outfile = *++args;
361160814Ssimon			}
362160814Ssimon		else if (!strcmp (*args, "-content"))
363160814Ssimon			{
364238405Sjkim			if (!args[1])
365238405Sjkim				goto argerr;
366238405Sjkim			contfile = *++args;
367160814Ssimon			}
368160814Ssimon		else if (args_verify(&args, NULL, &badarg, bio_err, &vpm))
369160814Ssimon			continue;
370238405Sjkim		else if ((cipher = EVP_get_cipherbyname(*args + 1)) == NULL)
371160814Ssimon			badarg = 1;
37259191Skris		args++;
373160814Ssimon		}
37459191Skris
375238405Sjkim	if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners))
376238405Sjkim		{
377238405Sjkim		BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
378238405Sjkim		goto argerr;
379238405Sjkim		}
380160814Ssimon
381238405Sjkim	if (operation & SMIME_SIGNERS)
382160814Ssimon		{
383238405Sjkim		/* Check to see if any final signer needs to be appended */
384238405Sjkim		if (keyfile && !signerfile)
385160814Ssimon			{
386238405Sjkim			BIO_puts(bio_err, "Illegal -inkey without -signer\n");
387238405Sjkim			goto argerr;
388238405Sjkim			}
389238405Sjkim		if (signerfile)
390238405Sjkim			{
391238405Sjkim			if (!sksigners)
392238405Sjkim				sksigners = sk_OPENSSL_STRING_new_null();
393238405Sjkim			sk_OPENSSL_STRING_push(sksigners, signerfile);
394238405Sjkim			if (!skkeys)
395238405Sjkim				skkeys = sk_OPENSSL_STRING_new_null();
396238405Sjkim			if (!keyfile)
397238405Sjkim				keyfile = signerfile;
398238405Sjkim			sk_OPENSSL_STRING_push(skkeys, keyfile);
399238405Sjkim			}
400238405Sjkim		if (!sksigners)
401238405Sjkim			{
40259191Skris			BIO_printf(bio_err, "No signer certificate specified\n");
40359191Skris			badarg = 1;
404160814Ssimon			}
405238405Sjkim		signerfile = NULL;
406238405Sjkim		keyfile = NULL;
407160814Ssimon		need_rand = 1;
40859191Skris		}
409160814Ssimon	else if (operation == SMIME_DECRYPT)
410160814Ssimon		{
411160814Ssimon		if (!recipfile && !keyfile)
412160814Ssimon			{
413160814Ssimon			BIO_printf(bio_err, "No recipient certificate or key specified\n");
41459191Skris			badarg = 1;
415160814Ssimon			}
41659191Skris		}
417160814Ssimon	else if (operation == SMIME_ENCRYPT)
418160814Ssimon		{
419160814Ssimon		if (!*args)
420160814Ssimon			{
42159191Skris			BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
42259191Skris			badarg = 1;
423160814Ssimon			}
424160814Ssimon		need_rand = 1;
42559191Skris		}
426160814Ssimon	else if (!operation)
427160814Ssimon		badarg = 1;
42859191Skris
429160814Ssimon	if (badarg)
430160814Ssimon		{
431238405Sjkim		argerr:
43259191Skris		BIO_printf (bio_err, "Usage smime [options] cert.pem ...\n");
43359191Skris		BIO_printf (bio_err, "where options are\n");
43459191Skris		BIO_printf (bio_err, "-encrypt       encrypt message\n");
43559191Skris		BIO_printf (bio_err, "-decrypt       decrypt encrypted message\n");
43659191Skris		BIO_printf (bio_err, "-sign          sign message\n");
43759191Skris		BIO_printf (bio_err, "-verify        verify signed message\n");
43859191Skris		BIO_printf (bio_err, "-pk7out        output PKCS#7 structure\n");
439109998Smarkm#ifndef OPENSSL_NO_DES
44059191Skris		BIO_printf (bio_err, "-des3          encrypt with triple DES\n");
44159191Skris		BIO_printf (bio_err, "-des           encrypt with DES\n");
44259191Skris#endif
443194206Ssimon#ifndef OPENSSL_NO_SEED
444194206Ssimon		BIO_printf (bio_err, "-seed          encrypt with SEED\n");
445194206Ssimon#endif
446109998Smarkm#ifndef OPENSSL_NO_RC2
44759191Skris		BIO_printf (bio_err, "-rc2-40        encrypt with RC2-40 (default)\n");
44859191Skris		BIO_printf (bio_err, "-rc2-64        encrypt with RC2-64\n");
44959191Skris		BIO_printf (bio_err, "-rc2-128       encrypt with RC2-128\n");
45059191Skris#endif
451109998Smarkm#ifndef OPENSSL_NO_AES
452109998Smarkm		BIO_printf (bio_err, "-aes128, -aes192, -aes256\n");
453109998Smarkm		BIO_printf (bio_err, "               encrypt PEM output with cbc aes\n");
454109998Smarkm#endif
455162911Ssimon#ifndef OPENSSL_NO_CAMELLIA
456162911Ssimon		BIO_printf (bio_err, "-camellia128, -camellia192, -camellia256\n");
457162911Ssimon		BIO_printf (bio_err, "               encrypt PEM output with cbc camellia\n");
458162911Ssimon#endif
45959191Skris		BIO_printf (bio_err, "-nointern      don't search certificates in message for signer\n");
46059191Skris		BIO_printf (bio_err, "-nosigs        don't verify message signature\n");
46159191Skris		BIO_printf (bio_err, "-noverify      don't verify signers certificate\n");
46259191Skris		BIO_printf (bio_err, "-nocerts       don't include signers certificate when signing\n");
46359191Skris		BIO_printf (bio_err, "-nodetach      use opaque signing\n");
46459191Skris		BIO_printf (bio_err, "-noattr        don't include any signed attributes\n");
46559191Skris		BIO_printf (bio_err, "-binary        don't translate message to text\n");
46659191Skris		BIO_printf (bio_err, "-certfile file other certificates file\n");
46759191Skris		BIO_printf (bio_err, "-signer file   signer certificate file\n");
46859191Skris		BIO_printf (bio_err, "-recip  file   recipient certificate file for decryption\n");
46959191Skris		BIO_printf (bio_err, "-in file       input file\n");
47068651Skris		BIO_printf (bio_err, "-inform arg    input format SMIME (default), PEM or DER\n");
47159191Skris		BIO_printf (bio_err, "-inkey file    input private key (if not signer or recipient)\n");
472109998Smarkm		BIO_printf (bio_err, "-keyform arg   input private key format (PEM or ENGINE)\n");
47359191Skris		BIO_printf (bio_err, "-out file      output file\n");
47468651Skris		BIO_printf (bio_err, "-outform arg   output format SMIME (default), PEM or DER\n");
47568651Skris		BIO_printf (bio_err, "-content file  supply or override content for detached signature\n");
47659191Skris		BIO_printf (bio_err, "-to addr       to address\n");
47759191Skris		BIO_printf (bio_err, "-from ad       from address\n");
47859191Skris		BIO_printf (bio_err, "-subject s     subject\n");
47959191Skris		BIO_printf (bio_err, "-text          include or delete text MIME headers\n");
48059191Skris		BIO_printf (bio_err, "-CApath dir    trusted certificates directory\n");
48159191Skris		BIO_printf (bio_err, "-CAfile file   trusted certificates file\n");
482109998Smarkm		BIO_printf (bio_err, "-crl_check     check revocation status of signer's certificate using CRLs\n");
483109998Smarkm		BIO_printf (bio_err, "-crl_check_all check revocation status of signer's certificate chain using CRLs\n");
484111147Snectar#ifndef OPENSSL_NO_ENGINE
485109998Smarkm		BIO_printf (bio_err, "-engine e      use engine e, possibly a hardware device.\n");
486111147Snectar#endif
48779998Skris		BIO_printf (bio_err, "-passin arg    input file pass phrase source\n");
48859191Skris		BIO_printf(bio_err,  "-rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR);
48959191Skris		BIO_printf(bio_err,  "               load the file (or the files in the directory) into\n");
49059191Skris		BIO_printf(bio_err,  "               the random number generator\n");
49159191Skris		BIO_printf (bio_err, "cert.pem       recipient certificate(s) for encryption\n");
49259191Skris		goto end;
493160814Ssimon		}
49459191Skris
495111147Snectar#ifndef OPENSSL_NO_ENGINE
496109998Smarkm        e = setup_engine(bio_err, engine, 0);
497111147Snectar#endif
498109998Smarkm
499160814Ssimon	if (!app_passwd(bio_err, passargin, NULL, &passin, NULL))
500160814Ssimon		{
50159191Skris		BIO_printf(bio_err, "Error getting password\n");
50259191Skris		goto end;
503160814Ssimon		}
50459191Skris
505160814Ssimon	if (need_rand)
506160814Ssimon		{
50759191Skris		app_RAND_load_file(NULL, bio_err, (inrand != NULL));
50859191Skris		if (inrand != NULL)
50959191Skris			BIO_printf(bio_err,"%ld semi-random bytes loaded\n",
51059191Skris				app_RAND_load_files(inrand));
511160814Ssimon		}
51259191Skris
51359191Skris	ret = 2;
51459191Skris
515238405Sjkim	if (!(operation & SMIME_SIGNERS))
516160814Ssimon		flags &= ~PKCS7_DETACHED;
51759191Skris
518160814Ssimon	if (operation & SMIME_OP)
519160814Ssimon		{
520160814Ssimon		if (outformat == FORMAT_ASN1)
521160814Ssimon			outmode = "wb";
522160814Ssimon		}
523160814Ssimon	else
524160814Ssimon		{
525160814Ssimon		if (flags & PKCS7_BINARY)
526160814Ssimon			outmode = "wb";
527238405Sjkim		}
528238405Sjkim
529238405Sjkim	if (operation & SMIME_IP)
530238405Sjkim		{
531160814Ssimon		if (informat == FORMAT_ASN1)
532160814Ssimon			inmode = "rb";
533160814Ssimon		}
534238405Sjkim	else
535238405Sjkim		{
536238405Sjkim		if (flags & PKCS7_BINARY)
537238405Sjkim			inmode = "rb";
538238405Sjkim		}
53959191Skris
540160814Ssimon	if (operation == SMIME_ENCRYPT)
541160814Ssimon		{
542160814Ssimon		if (!cipher)
543160814Ssimon			{
544279264Sdelphij#ifndef OPENSSL_NO_DES
545279264Sdelphij			cipher = EVP_des_ede3_cbc();
54659191Skris#else
54759191Skris			BIO_printf(bio_err, "No cipher selected\n");
54859191Skris			goto end;
54959191Skris#endif
550160814Ssimon			}
55159191Skris		encerts = sk_X509_new_null();
552160814Ssimon		while (*args)
553160814Ssimon			{
554160814Ssimon			if (!(cert = load_cert(bio_err,*args,FORMAT_PEM,
555160814Ssimon				NULL, e, "recipient certificate file")))
556160814Ssimon				{
557109998Smarkm#if 0				/* An appropriate message is already printed */
55859191Skris				BIO_printf(bio_err, "Can't read recipient certificate file %s\n", *args);
559109998Smarkm#endif
56059191Skris				goto end;
561160814Ssimon				}
56259191Skris			sk_X509_push(encerts, cert);
56359191Skris			cert = NULL;
56459191Skris			args++;
565160814Ssimon			}
56659191Skris		}
56759191Skris
568160814Ssimon	if (certfile)
569160814Ssimon		{
570160814Ssimon		if (!(other = load_certs(bio_err,certfile,FORMAT_PEM, NULL,
571160814Ssimon			e, "certificate file")))
572160814Ssimon			{
57359191Skris			ERR_print_errors(bio_err);
57459191Skris			goto end;
575160814Ssimon			}
57659191Skris		}
57759191Skris
578160814Ssimon	if (recipfile && (operation == SMIME_DECRYPT))
579160814Ssimon		{
580160814Ssimon		if (!(recip = load_cert(bio_err,recipfile,FORMAT_PEM,NULL,
581160814Ssimon			e, "recipient certificate file")))
582160814Ssimon			{
58359191Skris			ERR_print_errors(bio_err);
58459191Skris			goto end;
585160814Ssimon			}
58659191Skris		}
58759191Skris
588160814Ssimon	if (operation == SMIME_DECRYPT)
589160814Ssimon		{
590160814Ssimon		if (!keyfile)
591160814Ssimon			keyfile = recipfile;
592160814Ssimon		}
593160814Ssimon	else if (operation == SMIME_SIGN)
594160814Ssimon		{
595160814Ssimon		if (!keyfile)
596160814Ssimon			keyfile = signerfile;
597160814Ssimon		}
598160814Ssimon	else keyfile = NULL;
59959191Skris
600160814Ssimon	if (keyfile)
601160814Ssimon		{
602109998Smarkm		key = load_key(bio_err, keyfile, keyform, 0, passin, e,
603109998Smarkm			       "signing key file");
604160814Ssimon		if (!key)
60559191Skris			goto end;
606160814Ssimon		}
60759191Skris
608160814Ssimon	if (infile)
609160814Ssimon		{
610160814Ssimon		if (!(in = BIO_new_file(infile, inmode)))
611160814Ssimon			{
61259191Skris			BIO_printf (bio_err,
61359191Skris				 "Can't open input file %s\n", infile);
61459191Skris			goto end;
615160814Ssimon			}
61659191Skris		}
617160814Ssimon	else
618160814Ssimon		in = BIO_new_fp(stdin, BIO_NOCLOSE);
61959191Skris
620238405Sjkim	if (operation & SMIME_IP)
621238405Sjkim		{
622238405Sjkim		if (informat == FORMAT_SMIME)
623238405Sjkim			p7 = SMIME_read_PKCS7(in, &indata);
624238405Sjkim		else if (informat == FORMAT_PEM)
625238405Sjkim			p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
626238405Sjkim		else if (informat == FORMAT_ASN1)
627238405Sjkim			p7 = d2i_PKCS7_bio(in, NULL);
628238405Sjkim		else
629238405Sjkim			{
630238405Sjkim			BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
631238405Sjkim			goto end;
632238405Sjkim			}
633238405Sjkim
634238405Sjkim		if (!p7)
635238405Sjkim			{
636238405Sjkim			BIO_printf(bio_err, "Error reading S/MIME message\n");
637238405Sjkim			goto end;
638238405Sjkim			}
639238405Sjkim		if (contfile)
640238405Sjkim			{
641238405Sjkim			BIO_free(indata);
642238405Sjkim			if (!(indata = BIO_new_file(contfile, "rb")))
643238405Sjkim				{
644238405Sjkim				BIO_printf(bio_err, "Can't read content file %s\n", contfile);
645238405Sjkim				goto end;
646238405Sjkim				}
647238405Sjkim			}
648238405Sjkim		}
649238405Sjkim
650160814Ssimon	if (outfile)
651160814Ssimon		{
652160814Ssimon		if (!(out = BIO_new_file(outfile, outmode)))
653160814Ssimon			{
65459191Skris			BIO_printf (bio_err,
65559191Skris				 "Can't open output file %s\n", outfile);
65659191Skris			goto end;
657160814Ssimon			}
65859191Skris		}
659160814Ssimon	else
660160814Ssimon		{
66168651Skris		out = BIO_new_fp(stdout, BIO_NOCLOSE);
662109998Smarkm#ifdef OPENSSL_SYS_VMS
66368651Skris		{
66468651Skris		    BIO *tmpbio = BIO_new(BIO_f_linebuffer());
66568651Skris		    out = BIO_push(tmpbio, out);
66668651Skris		}
66768651Skris#endif
668160814Ssimon		}
66959191Skris
670160814Ssimon	if (operation == SMIME_VERIFY)
671160814Ssimon		{
672160814Ssimon		if (!(store = setup_verify(bio_err, CAfile, CApath)))
673160814Ssimon			goto end;
674238405Sjkim		X509_STORE_set_verify_cb(store, smime_cb);
675160814Ssimon		if (vpm)
676160814Ssimon			X509_STORE_set1_param(store, vpm);
677160814Ssimon		}
67859191Skris
679109998Smarkm
68059191Skris	ret = 3;
68159191Skris
682160814Ssimon	if (operation == SMIME_ENCRYPT)
683160814Ssimon		{
684238405Sjkim		if (indef)
685160814Ssimon			flags |= PKCS7_STREAM;
686238405Sjkim		p7 = PKCS7_encrypt(encerts, in, cipher, flags);
687100928Snectar		}
688238405Sjkim	else if (operation & SMIME_SIGNERS)
689160814Ssimon		{
690238405Sjkim		int i;
691238405Sjkim		/* If detached data content we only enable streaming if
692238405Sjkim		 * S/MIME output format.
693238405Sjkim		 */
694238405Sjkim		if (operation == SMIME_SIGN)
695160814Ssimon			{
696238405Sjkim			if (flags & PKCS7_DETACHED)
697238405Sjkim				{
698238405Sjkim				if (outformat == FORMAT_SMIME)
699238405Sjkim					flags |= PKCS7_STREAM;
700238405Sjkim				}
701238405Sjkim			else if (indef)
702238405Sjkim				flags |= PKCS7_STREAM;
703238405Sjkim			flags |= PKCS7_PARTIAL;
704238405Sjkim			p7 = PKCS7_sign(NULL, NULL, other, in, flags);
705238405Sjkim			if (!p7)
706238405Sjkim				goto end;
707160814Ssimon			}
708238405Sjkim		else
709238405Sjkim			flags |= PKCS7_REUSE_DIGEST;
710238405Sjkim		for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++)
711160814Ssimon			{
712238405Sjkim			signerfile = sk_OPENSSL_STRING_value(sksigners, i);
713238405Sjkim			keyfile = sk_OPENSSL_STRING_value(skkeys, i);
714238405Sjkim			signer = load_cert(bio_err, signerfile,FORMAT_PEM, NULL,
715238405Sjkim					e, "signer certificate");
716238405Sjkim			if (!signer)
717238405Sjkim				goto end;
718238405Sjkim			key = load_key(bio_err, keyfile, keyform, 0, passin, e,
719238405Sjkim			       "signing key file");
720238405Sjkim			if (!key)
721238405Sjkim				goto end;
722238405Sjkim			if (!PKCS7_sign_add_signer(p7, signer, key,
723238405Sjkim						sign_md, flags))
724238405Sjkim				goto end;
725238405Sjkim			X509_free(signer);
726238405Sjkim			signer = NULL;
727238405Sjkim			EVP_PKEY_free(key);
728238405Sjkim			key = NULL;
729160814Ssimon			}
730238405Sjkim		/* If not streaming or resigning finalize structure */
731238405Sjkim		if ((operation == SMIME_SIGN) && !(flags & PKCS7_STREAM))
732160814Ssimon			{
733238405Sjkim			if (!PKCS7_final(p7, in, flags))
73468651Skris				goto end;
73568651Skris			}
73668651Skris		}
73759191Skris
738160814Ssimon	if (!p7)
739160814Ssimon		{
74059191Skris		BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
74159191Skris		goto end;
742160814Ssimon		}
74359191Skris
74459191Skris	ret = 4;
745160814Ssimon	if (operation == SMIME_DECRYPT)
746160814Ssimon		{
747160814Ssimon		if (!PKCS7_decrypt(p7, key, recip, out, flags))
748160814Ssimon			{
74959191Skris			BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n");
75059191Skris			goto end;
751160814Ssimon			}
75259191Skris		}
753160814Ssimon	else if (operation == SMIME_VERIFY)
754160814Ssimon		{
75559191Skris		STACK_OF(X509) *signers;
756160814Ssimon		if (PKCS7_verify(p7, other, store, indata, out, flags))
757100928Snectar			BIO_printf(bio_err, "Verification successful\n");
758160814Ssimon		else
759160814Ssimon			{
760100928Snectar			BIO_printf(bio_err, "Verification failure\n");
76159191Skris			goto end;
762160814Ssimon			}
76359191Skris		signers = PKCS7_get0_signers(p7, other, flags);
764160814Ssimon		if (!save_certs(signerfile, signers))
765160814Ssimon			{
76659191Skris			BIO_printf(bio_err, "Error writing signers to %s\n",
76759191Skris								signerfile);
76859191Skris			ret = 5;
76959191Skris			goto end;
770160814Ssimon			}
771160814Ssimon		sk_X509_free(signers);
77259191Skris		}
773160814Ssimon	else if (operation == SMIME_PK7OUT)
77459191Skris		PEM_write_bio_PKCS7(out, p7);
775160814Ssimon	else
776160814Ssimon		{
777160814Ssimon		if (to)
778160814Ssimon			BIO_printf(out, "To: %s\n", to);
779160814Ssimon		if (from)
780160814Ssimon			BIO_printf(out, "From: %s\n", from);
781160814Ssimon		if (subject)
782160814Ssimon			BIO_printf(out, "Subject: %s\n", subject);
783160814Ssimon		if (outformat == FORMAT_SMIME)
784238405Sjkim			{
785238405Sjkim			if (operation == SMIME_RESIGN)
786238405Sjkim				SMIME_write_PKCS7(out, p7, indata, flags);
787238405Sjkim			else
788238405Sjkim				SMIME_write_PKCS7(out, p7, in, flags);
789238405Sjkim			}
790160814Ssimon		else if (outformat == FORMAT_PEM)
791238405Sjkim			PEM_write_bio_PKCS7_stream(out, p7, in, flags);
792160814Ssimon		else if (outformat == FORMAT_ASN1)
793238405Sjkim			i2d_PKCS7_bio_stream(out,p7, in, flags);
794160814Ssimon		else
795160814Ssimon			{
79668651Skris			BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
79768651Skris			goto end;
798160814Ssimon			}
79968651Skris		}
80059191Skris	ret = 0;
80159191Skrisend:
80259191Skris	if (need_rand)
80359191Skris		app_RAND_write_file(NULL, bio_err);
804160814Ssimon	if (ret) ERR_print_errors(bio_err);
80559191Skris	sk_X509_pop_free(encerts, X509_free);
80659191Skris	sk_X509_pop_free(other, X509_free);
807160814Ssimon	if (vpm)
808160814Ssimon		X509_VERIFY_PARAM_free(vpm);
809238405Sjkim	if (sksigners)
810238405Sjkim		sk_OPENSSL_STRING_free(sksigners);
811238405Sjkim	if (skkeys)
812238405Sjkim		sk_OPENSSL_STRING_free(skkeys);
81359191Skris	X509_STORE_free(store);
81459191Skris	X509_free(cert);
81559191Skris	X509_free(recip);
81659191Skris	X509_free(signer);
81759191Skris	EVP_PKEY_free(key);
81859191Skris	PKCS7_free(p7);
81959191Skris	BIO_free(in);
82059191Skris	BIO_free(indata);
82168651Skris	BIO_free_all(out);
822160814Ssimon	if (passin) OPENSSL_free(passin);
82359191Skris	return (ret);
82459191Skris}
82559191Skris
82659191Skrisstatic int save_certs(char *signerfile, STACK_OF(X509) *signers)
827160814Ssimon	{
82859191Skris	int i;
82959191Skris	BIO *tmp;
830160814Ssimon	if (!signerfile)
831160814Ssimon		return 1;
83259191Skris	tmp = BIO_new_file(signerfile, "w");
833160814Ssimon	if (!tmp) return 0;
83459191Skris	for(i = 0; i < sk_X509_num(signers); i++)
83559191Skris		PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
83659191Skris	BIO_free(tmp);
83759191Skris	return 1;
838160814Ssimon	}
83959191Skris
840160814Ssimon
841160814Ssimon/* Minimal callback just to output policy info (if any) */
842160814Ssimon
843160814Ssimonstatic int smime_cb(int ok, X509_STORE_CTX *ctx)
844160814Ssimon	{
845160814Ssimon	int error;
846160814Ssimon
847160814Ssimon	error = X509_STORE_CTX_get_error(ctx);
848160814Ssimon
849160814Ssimon	if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
850160814Ssimon		&& ((error != X509_V_OK) || (ok != 2)))
851160814Ssimon		return ok;
852160814Ssimon
853160814Ssimon	policies_print(NULL, ctx);
854160814Ssimon
855160814Ssimon	return ok;
856160814Ssimon
857160814Ssimon	}
858