xref: /dragonfly/crypto/libressl/apps/openssl/smime.c (revision 6f5ec8b5)
1 /* $OpenBSD: smime.c,v 1.17 2022/01/16 07:12:28 inoguchi 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 static struct {
86 	char *CAfile;
87 	char *CApath;
88 	char *certfile;
89 	const EVP_CIPHER *cipher;
90 	char *contfile;
91 	int flags;
92 	char *from;
93 	int indef;
94 	char *infile;
95 	int informat;
96 	char *keyfile;
97 	int keyform;
98 	int operation;
99 	char *outfile;
100 	int outformat;
101 	char *passargin;
102 	char *recipfile;
103 	const EVP_MD *sign_md;
104 	char *signerfile;
105 	STACK_OF(OPENSSL_STRING) *skkeys;
106 	STACK_OF(OPENSSL_STRING) *sksigners;
107 	char *subject;
108 	char *to;
109 	X509_VERIFY_PARAM *vpm;
110 } smime_config;
111 
112 static const EVP_CIPHER *
113 get_cipher_by_name(char *name)
114 {
115 	if (name == NULL || strcmp(name, "") == 0)
116 		return (NULL);
117 #ifndef OPENSSL_NO_AES
118 	else if (strcmp(name, "aes128") == 0)
119 		return EVP_aes_128_cbc();
120 	else if (strcmp(name, "aes192") == 0)
121 		return EVP_aes_192_cbc();
122 	else if (strcmp(name, "aes256") == 0)
123 		return EVP_aes_256_cbc();
124 #endif
125 #ifndef OPENSSL_NO_CAMELLIA
126 	else if (strcmp(name, "camellia128") == 0)
127 		return EVP_camellia_128_cbc();
128 	else if (strcmp(name, "camellia192") == 0)
129 		return EVP_camellia_192_cbc();
130 	else if (strcmp(name, "camellia256") == 0)
131 		return EVP_camellia_256_cbc();
132 #endif
133 #ifndef OPENSSL_NO_DES
134 	else if (strcmp(name, "des") == 0)
135 		return EVP_des_cbc();
136 	else if (strcmp(name, "des3") == 0)
137 		return EVP_des_ede3_cbc();
138 #endif
139 #ifndef OPENSSL_NO_RC2
140 	else if (!strcmp(name, "rc2-40"))
141 		return EVP_rc2_40_cbc();
142 	else if (!strcmp(name, "rc2-64"))
143 		return EVP_rc2_64_cbc();
144 	else if (!strcmp(name, "rc2-128"))
145 		return EVP_rc2_cbc();
146 #endif
147 	else
148 		return NULL;
149 }
150 
151 static int
152 smime_opt_cipher(int argc, char **argv, int *argsused)
153 {
154 	char *name = argv[0];
155 
156 	if (*name++ != '-')
157 		return (1);
158 
159 	if ((smime_config.cipher = get_cipher_by_name(name)) == NULL)
160 		if ((smime_config.cipher = EVP_get_cipherbyname(name)) == NULL)
161 			return (1);
162 
163 	*argsused = 1;
164 	return (0);
165 }
166 
167 static int
168 smime_opt_inkey(char *arg)
169 {
170 	if (smime_config.keyfile == NULL) {
171 		smime_config.keyfile = arg;
172 		return (0);
173 	}
174 
175 	if (smime_config.signerfile == NULL) {
176 		BIO_puts(bio_err, "Illegal -inkey without -signer\n");
177 		return (1);
178 	}
179 
180 	if (smime_config.sksigners == NULL) {
181 		if ((smime_config.sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
182 			return (1);
183 	}
184 	if (!sk_OPENSSL_STRING_push(smime_config.sksigners,
185 	    smime_config.signerfile))
186 		return (1);
187 
188 	smime_config.signerfile = NULL;
189 
190 	if (smime_config.skkeys == NULL) {
191 		if ((smime_config.skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
192 			return (1);
193 	}
194 	if (!sk_OPENSSL_STRING_push(smime_config.skkeys, smime_config.keyfile))
195 		return (1);
196 
197 	smime_config.keyfile = arg;
198 	return (0);
199 }
200 
201 static int
202 smime_opt_md(char *arg)
203 {
204 	if ((smime_config.sign_md = EVP_get_digestbyname(arg)) == NULL) {
205 		BIO_printf(bio_err, "Unknown digest %s\n", arg);
206 		return (1);
207 	}
208 	return (0);
209 }
210 
211 static int
212 smime_opt_signer(char *arg)
213 {
214 	if (smime_config.signerfile == NULL) {
215 		smime_config.signerfile = arg;
216 		return (0);
217 	}
218 
219 	if (smime_config.sksigners == NULL) {
220 		if ((smime_config.sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
221 			return (1);
222 	}
223 	if (!sk_OPENSSL_STRING_push(smime_config.sksigners,
224 	    smime_config.signerfile))
225 		return (1);
226 
227 	if (smime_config.keyfile == NULL)
228 		smime_config.keyfile = smime_config.signerfile;
229 
230 	if (smime_config.skkeys == NULL) {
231 		if ((smime_config.skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
232 			return (1);
233 	}
234 	if (!sk_OPENSSL_STRING_push(smime_config.skkeys, smime_config.keyfile))
235 		return (1);
236 
237 	smime_config.keyfile = NULL;
238 
239 	smime_config.signerfile = arg;
240 	return (0);
241 }
242 
243 static int
244 smime_opt_verify_param(int argc, char **argv, int *argsused)
245 {
246 	int oargc = argc;
247 	int badarg = 0;
248 
249 	if (!args_verify(&argv, &argc, &badarg, bio_err, &smime_config.vpm))
250 		return (1);
251 	if (badarg)
252 		return (1);
253 
254 	*argsused = oargc - argc;
255 
256 	return (0);
257 }
258 
259 static const struct option smime_options[] = {
260 #ifndef OPENSSL_NO_AES
261 	{
262 		.name = "aes128",
263 		.desc = "Encrypt PEM output with CBC AES",
264 		.type = OPTION_ARGV_FUNC,
265 		.opt.argvfunc = smime_opt_cipher,
266 	},
267 	{
268 		.name = "aes192",
269 		.desc = "Encrypt PEM output with CBC AES",
270 		.type = OPTION_ARGV_FUNC,
271 		.opt.argvfunc = smime_opt_cipher,
272 	},
273 	{
274 		.name = "aes256",
275 		.desc = "Encrypt PEM output with CBC AES",
276 		.type = OPTION_ARGV_FUNC,
277 		.opt.argvfunc = smime_opt_cipher,
278 	},
279 #endif
280 #ifndef OPENSSL_NO_CAMELLIA
281 	{
282 		.name = "camellia128",
283 		.desc = "Encrypt PEM output with CBC Camellia",
284 		.type = OPTION_ARGV_FUNC,
285 		.opt.argvfunc = smime_opt_cipher,
286 	},
287 	{
288 		.name = "camellia192",
289 		.desc = "Encrypt PEM output with CBC Camellia",
290 		.type = OPTION_ARGV_FUNC,
291 		.opt.argvfunc = smime_opt_cipher,
292 	},
293 	{
294 		.name = "camellia256",
295 		.desc = "Encrypt PEM output with CBC Camellia",
296 		.type = OPTION_ARGV_FUNC,
297 		.opt.argvfunc = smime_opt_cipher,
298 	},
299 #endif
300 #ifndef OPENSSL_NO_DES
301 	{
302 		.name = "des",
303 		.desc = "Encrypt with DES",
304 		.type = OPTION_ARGV_FUNC,
305 		.opt.argvfunc = smime_opt_cipher,
306 	},
307 	{
308 		.name = "des3",
309 		.desc = "Encrypt with triple DES",
310 		.type = OPTION_ARGV_FUNC,
311 		.opt.argvfunc = smime_opt_cipher,
312 	},
313 #endif
314 #ifndef OPENSSL_NO_RC2
315 	{
316 		.name = "rc2-40",
317 		.desc = "Encrypt with RC2-40 (default)",
318 		.type = OPTION_ARGV_FUNC,
319 		.opt.argvfunc = smime_opt_cipher,
320 	},
321 	{
322 		.name = "rc2-64",
323 		.desc = "Encrypt with RC2-64",
324 		.type = OPTION_ARGV_FUNC,
325 		.opt.argvfunc = smime_opt_cipher,
326 	},
327 	{
328 		.name = "rc2-128",
329 		.desc = "Encrypt with RC2-128",
330 		.type = OPTION_ARGV_FUNC,
331 		.opt.argvfunc = smime_opt_cipher,
332 	},
333 #endif
334 	{
335 		.name = "CAfile",
336 		.argname = "file",
337 		.desc = "Certificate Authority file",
338 		.type = OPTION_ARG,
339 		.opt.arg = &smime_config.CAfile,
340 	},
341 	{
342 		.name = "CApath",
343 		.argname = "path",
344 		.desc = "Certificate Authority path",
345 		.type = OPTION_ARG,
346 		.opt.arg = &smime_config.CApath,
347 	},
348 	{
349 		.name = "binary",
350 		.desc = "Do not translate message to text",
351 		.type = OPTION_VALUE_OR,
352 		.opt.value = &smime_config.flags,
353 		.value = PKCS7_BINARY,
354 	},
355 	{
356 		.name = "certfile",
357 		.argname = "file",
358 		.desc = "Other certificates file",
359 		.type = OPTION_ARG,
360 		.opt.arg = &smime_config.certfile,
361 	},
362 	{
363 		.name = "content",
364 		.argname = "file",
365 		.desc = "Supply or override content for detached signature",
366 		.type = OPTION_ARG,
367 		.opt.arg = &smime_config.contfile,
368 	},
369 	{
370 		.name = "crlfeol",
371 		.desc = "Use CRLF as EOL termination instead of CR only",
372 		.type = OPTION_VALUE_OR,
373 		.opt.value = &smime_config.flags,
374 		.value = PKCS7_CRLFEOL,
375 	},
376 	{
377 		.name = "decrypt",
378 		.desc = "Decrypt encrypted message",
379 		.type = OPTION_VALUE,
380 		.opt.value = &smime_config.operation,
381 		.value = SMIME_DECRYPT,
382 	},
383 	{
384 		.name = "encrypt",
385 		.desc = "Encrypt message",
386 		.type = OPTION_VALUE,
387 		.opt.value = &smime_config.operation,
388 		.value = SMIME_ENCRYPT,
389 	},
390 	{
391 		.name = "from",
392 		.argname = "addr",
393 		.desc = "From address",
394 		.type = OPTION_ARG,
395 		.opt.arg = &smime_config.from,
396 	},
397 	{
398 		.name = "in",
399 		.argname = "file",
400 		.desc = "Input file",
401 		.type = OPTION_ARG,
402 		.opt.arg = &smime_config.infile,
403 	},
404 	{
405 		.name = "indef",
406 		.desc = "Same as -stream",
407 		.type = OPTION_VALUE,
408 		.opt.value = &smime_config.indef,
409 		.value = 1,
410 	},
411 	{
412 		.name = "inform",
413 		.argname = "fmt",
414 		.desc = "Input format (DER, PEM or SMIME (default))",
415 		.type = OPTION_ARG_FORMAT,
416 		.opt.value = &smime_config.informat,
417 	},
418 	{
419 		.name = "inkey",
420 		.argname = "file",
421 		.desc = "Input key file",
422 		.type = OPTION_ARG_FUNC,
423 		.opt.argfunc = smime_opt_inkey,
424 	},
425 	{
426 		.name = "keyform",
427 		.argname = "fmt",
428 		.desc = "Input key format (DER or PEM (default))",
429 		.type = OPTION_ARG_FORMAT,
430 		.opt.value = &smime_config.keyform,
431 	},
432 	{
433 		.name = "md",
434 		.argname = "digest",
435 		.desc = "Digest to use when signing or resigning",
436 		.type = OPTION_ARG_FUNC,
437 		.opt.argfunc = smime_opt_md,
438 	},
439 	{
440 		.name = "noattr",
441 		.desc = "Do not include any signed attributes",
442 		.type = OPTION_VALUE_OR,
443 		.opt.value = &smime_config.flags,
444 		.value = PKCS7_NOATTR,
445 	},
446 	{
447 		.name = "nocerts",
448 		.desc = "Do not include signer's certificate when signing",
449 		.type = OPTION_VALUE_OR,
450 		.opt.value = &smime_config.flags,
451 		.value = PKCS7_NOCERTS,
452 	},
453 	{
454 		.name = "nochain",
455 		.desc = "Do not chain verification of signer's certificates",
456 		.type = OPTION_VALUE_OR,
457 		.opt.value = &smime_config.flags,
458 		.value = PKCS7_NOCHAIN,
459 	},
460 	{
461 		.name = "nodetach",
462 		.desc = "Use opaque signing",
463 		.type = OPTION_VALUE_AND,
464 		.opt.value = &smime_config.flags,
465 		.value = ~PKCS7_DETACHED,
466 	},
467 	{
468 		.name = "noindef",
469 		.desc = "Disable streaming I/O",
470 		.type = OPTION_VALUE,
471 		.opt.value = &smime_config.indef,
472 		.value = 0,
473 	},
474 	{
475 		.name = "nointern",
476 		.desc = "Do not search certificates in message for signer",
477 		.type = OPTION_VALUE_OR,
478 		.opt.value = &smime_config.flags,
479 		.value = PKCS7_NOINTERN,
480 	},
481 	{
482 		.name = "nooldmime",
483 		.desc = "Output old S/MIME content type",
484 		.type = OPTION_VALUE_OR,
485 		.opt.value = &smime_config.flags,
486 		.value = PKCS7_NOOLDMIMETYPE,
487 	},
488 	{
489 		.name = "nosigs",
490 		.desc = "Do not verify message signature",
491 		.type = OPTION_VALUE_OR,
492 		.opt.value = &smime_config.flags,
493 		.value = PKCS7_NOSIGS,
494 	},
495 	{
496 		.name = "nosmimecap",
497 		.desc = "Omit the SMIMECapabilities attribute",
498 		.type = OPTION_VALUE_OR,
499 		.opt.value = &smime_config.flags,
500 		.value = PKCS7_NOSMIMECAP,
501 	},
502 	{
503 		.name = "noverify",
504 		.desc = "Do not verify signer's certificate",
505 		.type = OPTION_VALUE_OR,
506 		.opt.value = &smime_config.flags,
507 		.value = PKCS7_NOVERIFY,
508 	},
509 	{
510 		.name = "out",
511 		.argname = "file",
512 		.desc = "Output file",
513 		.type = OPTION_ARG,
514 		.opt.arg = &smime_config.outfile,
515 	},
516 	{
517 		.name = "outform",
518 		.argname = "fmt",
519 		.desc = "Output format (DER, PEM or SMIME (default))",
520 		.type = OPTION_ARG_FORMAT,
521 		.opt.value = &smime_config.outformat,
522 	},
523 	{
524 		.name = "passin",
525 		.argname = "src",
526 		.desc = "Private key password source",
527 		.type = OPTION_ARG,
528 		.opt.arg = &smime_config.passargin,
529 	},
530 	{
531 		.name = "pk7out",
532 		.desc = "Output PKCS#7 structure",
533 		.type = OPTION_VALUE,
534 		.opt.value = &smime_config.operation,
535 		.value = SMIME_PK7OUT,
536 	},
537 	{
538 		.name = "recip",
539 		.argname = "file",
540 		.desc = "Recipient certificate file for decryption",
541 		.type = OPTION_ARG,
542 		.opt.arg = &smime_config.recipfile,
543 	},
544 	{
545 		.name = "resign",
546 		.desc = "Resign a signed message",
547 		.type = OPTION_VALUE,
548 		.opt.value = &smime_config.operation,
549 		.value = SMIME_RESIGN,
550 	},
551 	{
552 		.name = "sign",
553 		.desc = "Sign message",
554 		.type = OPTION_VALUE,
555 		.opt.value = &smime_config.operation,
556 		.value = SMIME_SIGN,
557 	},
558 	{
559 		.name = "signer",
560 		.argname = "file",
561 		.desc = "Signer certificate file",
562 		.type = OPTION_ARG_FUNC,
563 		.opt.argfunc = smime_opt_signer,
564 	},
565 	{
566 		.name = "stream",
567 		.desc = "Enable streaming I/O",
568 		.type = OPTION_VALUE,
569 		.opt.value = &smime_config.indef,
570 		.value = 1,
571 	},
572 	{
573 		.name = "subject",
574 		.argname = "s",
575 		.desc = "Subject",
576 		.type = OPTION_ARG,
577 		.opt.arg = &smime_config.subject,
578 	},
579 	{
580 		.name = "text",
581 		.desc = "Include or delete text MIME headers",
582 		.type = OPTION_VALUE_OR,
583 		.opt.value = &smime_config.flags,
584 		.value = PKCS7_TEXT,
585 	},
586 	{
587 		.name = "to",
588 		.argname = "addr",
589 		.desc = "To address",
590 		.type = OPTION_ARG,
591 		.opt.arg = &smime_config.to,
592 	},
593 	{
594 		.name = "verify",
595 		.desc = "Verify signed message",
596 		.type = OPTION_VALUE,
597 		.opt.value = &smime_config.operation,
598 		.value = SMIME_VERIFY,
599 	},
600 	{
601 		.name = "check_ss_sig",
602 		.type = OPTION_ARGV_FUNC,
603 		.opt.argvfunc = smime_opt_verify_param,
604 	},
605 	{
606 		.name = "crl_check",
607 		.type = OPTION_ARGV_FUNC,
608 		.opt.argvfunc = smime_opt_verify_param,
609 	},
610 	{
611 		.name = "crl_check_all",
612 		.type = OPTION_ARGV_FUNC,
613 		.opt.argvfunc = smime_opt_verify_param,
614 	},
615 	{
616 		.name = "extended_crl",
617 		.type = OPTION_ARGV_FUNC,
618 		.opt.argvfunc = smime_opt_verify_param,
619 	},
620 	{
621 		.name = "ignore_critical",
622 		.type = OPTION_ARGV_FUNC,
623 		.opt.argvfunc = smime_opt_verify_param,
624 	},
625 	{
626 		.name = "issuer_checks",
627 		.type = OPTION_ARGV_FUNC,
628 		.opt.argvfunc = smime_opt_verify_param,
629 	},
630 	{
631 		.name = "policy_check",
632 		.type = OPTION_ARGV_FUNC,
633 		.opt.argvfunc = smime_opt_verify_param,
634 	},
635 	{
636 		.name = "x509_strict",
637 		.type = OPTION_ARGV_FUNC,
638 		.opt.argvfunc = smime_opt_verify_param,
639 	},
640 	{
641 		.name = NULL,
642 		.type = OPTION_ARGV_FUNC,
643 		.opt.argvfunc = smime_opt_cipher,
644 	},
645 	{ NULL },
646 };
647 
648 static const struct option verify_shared_options[] = {
649 	{
650 		.name = "check_ss_sig",
651 		.desc = "Check the root CA self-signed certificate signature",
652 	},
653 	{
654 		.name = "crl_check",
655 		.desc = "Enable CRL checking for the leaf certificate",
656 	},
657 	{
658 		.name = "crl_check_all",
659 		.desc = "Enable CRL checking for the entire certificate chain",
660 	},
661 	{
662 		.name = "extended_crl",
663 		.desc = "Enable extended CRL support",
664 	},
665 	{
666 		.name = "ignore_critical",
667 		.desc = "Disable critical extension checking",
668 	},
669 	{
670 		.name = "issuer_checks",
671 		.desc = "Enable debugging of certificate issuer checks",
672 	},
673 	{
674 		.name = "policy_check",
675 		.desc = "Enable certificate policy checking",
676 	},
677 	{
678 		.name = "x509_strict",
679 		.desc = "Use strict X.509 rules (disables workarounds)",
680 	},
681 	{ NULL },
682 };
683 
684 static void
685 smime_usage(void)
686 {
687 	fprintf(stderr, "usage: smime "
688 	    "[-aes128 | -aes192 | -aes256 | -des |\n"
689 	    "    -des3 | -rc2-40 | -rc2-64 | -rc2-128] [-binary]\n"
690 	    "    [-CAfile file] [-CApath directory] [-certfile file]\n"
691 	    "    [-content file]\n"
692 	    "    [-decrypt] [-encrypt]\n"
693 	    "    [-from addr] [-in file] [-indef]\n"
694 	    "    [-inform der | pem | smime] [-inkey file]\n"
695 	    "    [-keyform der | pem] [-md digest] [-noattr] [-nocerts]\n"
696 	    "    [-nochain] [-nodetach] [-noindef] [-nointern] [-nosigs]\n"
697 	    "    [-nosmimecap] [-noverify] [-out file]\n"
698 	    "    [-outform der | pem | smime] [-passin arg] [-pk7out]\n"
699 	    "    [-recip file] [-resign] [-sign]\n"
700 	    "    [-signer file] [-stream] [-subject s] [-text] [-to addr]\n"
701 	    "    [-verify] [cert.pem ...]\n\n");
702 
703 	options_usage(smime_options);
704 
705 	fprintf(stderr, "\nVerification options:\n\n");
706 	options_usage(verify_shared_options);
707 }
708 
709 int
710 smime_main(int argc, char **argv)
711 {
712 	int ret = 0;
713 	char **args;
714 	int argsused = 0;
715 	const char *inmode = "r", *outmode = "w";
716 	PKCS7 *p7 = NULL;
717 	X509_STORE *store = NULL;
718 	X509 *cert = NULL, *recip = NULL, *signer = NULL;
719 	EVP_PKEY *key = NULL;
720 	STACK_OF(X509) *encerts = NULL, *other = NULL;
721 	BIO *in = NULL, *out = NULL, *indata = NULL;
722 	int badarg = 0;
723 	char *passin = NULL;
724 
725 	if (single_execution) {
726 		if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
727 			perror("pledge");
728 			exit(1);
729 		}
730 	}
731 
732 	memset(&smime_config, 0, sizeof(smime_config));
733 	smime_config.flags = PKCS7_DETACHED;
734 	smime_config.informat = FORMAT_SMIME;
735 	smime_config.outformat = FORMAT_SMIME;
736 	smime_config.keyform = FORMAT_PEM;
737 	if (options_parse(argc, argv, smime_options, NULL, &argsused) != 0) {
738 		goto argerr;
739 	}
740 	args = argv + argsused;
741 	ret = 1;
742 
743 	if (!(smime_config.operation & SMIME_SIGNERS) &&
744 	    (smime_config.skkeys != NULL || smime_config.sksigners != NULL)) {
745 		BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
746 		goto argerr;
747 	}
748 	if (smime_config.operation & SMIME_SIGNERS) {
749 		/* Check to see if any final signer needs to be appended */
750 		if (smime_config.keyfile != NULL &&
751 		    smime_config.signerfile == NULL) {
752 			BIO_puts(bio_err, "Illegal -inkey without -signer\n");
753 			goto argerr;
754 		}
755 		if (smime_config.signerfile != NULL) {
756 			if (smime_config.sksigners == NULL) {
757 				if ((smime_config.sksigners =
758 				    sk_OPENSSL_STRING_new_null()) == NULL)
759 					goto end;
760 			}
761 			if (!sk_OPENSSL_STRING_push(smime_config.sksigners,
762 			    smime_config.signerfile))
763 				goto end;
764 			if (smime_config.skkeys == NULL) {
765 				if ((smime_config.skkeys =
766 				    sk_OPENSSL_STRING_new_null()) == NULL)
767 					goto end;
768 			}
769 			if (smime_config.keyfile == NULL)
770 				smime_config.keyfile = smime_config.signerfile;
771 			if (!sk_OPENSSL_STRING_push(smime_config.skkeys,
772 			    smime_config.keyfile))
773 				goto end;
774 		}
775 		if (smime_config.sksigners == NULL) {
776 			BIO_printf(bio_err,
777 			    "No signer certificate specified\n");
778 			badarg = 1;
779 		}
780 		smime_config.signerfile = NULL;
781 		smime_config.keyfile = NULL;
782 	} else if (smime_config.operation == SMIME_DECRYPT) {
783 		if (smime_config.recipfile == NULL &&
784 		    smime_config.keyfile == NULL) {
785 			BIO_printf(bio_err,
786 			    "No recipient certificate or key specified\n");
787 			badarg = 1;
788 		}
789 	} else if (smime_config.operation == SMIME_ENCRYPT) {
790 		if (*args == NULL) {
791 			BIO_printf(bio_err,
792 			    "No recipient(s) certificate(s) specified\n");
793 			badarg = 1;
794 		}
795 	} else if (!smime_config.operation) {
796 		badarg = 1;
797 	}
798 
799 	if (badarg) {
800  argerr:
801 		smime_usage();
802 		goto end;
803 	}
804 
805 	if (!app_passwd(bio_err, smime_config.passargin, NULL, &passin, NULL)) {
806 		BIO_printf(bio_err, "Error getting password\n");
807 		goto end;
808 	}
809 	ret = 2;
810 
811 	if (!(smime_config.operation & SMIME_SIGNERS))
812 		smime_config.flags &= ~PKCS7_DETACHED;
813 
814 	if (smime_config.operation & SMIME_OP) {
815 		if (smime_config.outformat == FORMAT_ASN1)
816 			outmode = "wb";
817 	} else {
818 		if (smime_config.flags & PKCS7_BINARY)
819 			outmode = "wb";
820 	}
821 
822 	if (smime_config.operation & SMIME_IP) {
823 		if (smime_config.informat == FORMAT_ASN1)
824 			inmode = "rb";
825 	} else {
826 		if (smime_config.flags & PKCS7_BINARY)
827 			inmode = "rb";
828 	}
829 
830 	if (smime_config.operation == SMIME_ENCRYPT) {
831 		if (smime_config.cipher == NULL) {
832 #ifndef OPENSSL_NO_RC2
833 			smime_config.cipher = EVP_rc2_40_cbc();
834 #else
835 			BIO_printf(bio_err, "No cipher selected\n");
836 			goto end;
837 #endif
838 		}
839 		if ((encerts = sk_X509_new_null()) == NULL)
840 			goto end;
841 		while (*args != NULL) {
842 			if ((cert = load_cert(bio_err, *args, FORMAT_PEM,
843 			    NULL, "recipient certificate file")) == NULL) {
844 				goto end;
845 			}
846 			if (!sk_X509_push(encerts, cert))
847 				goto end;
848 			cert = NULL;
849 			args++;
850 		}
851 	}
852 	if (smime_config.certfile != NULL) {
853 		if ((other = load_certs(bio_err, smime_config.certfile,
854 		    FORMAT_PEM, NULL, "certificate file")) == NULL) {
855 			ERR_print_errors(bio_err);
856 			goto end;
857 		}
858 	}
859 	if (smime_config.recipfile != NULL &&
860 	    (smime_config.operation == SMIME_DECRYPT)) {
861 		if ((recip = load_cert(bio_err, smime_config.recipfile,
862 		    FORMAT_PEM, NULL, "recipient certificate file")) == NULL) {
863 			ERR_print_errors(bio_err);
864 			goto end;
865 		}
866 	}
867 	if (smime_config.operation == SMIME_DECRYPT) {
868 		if (smime_config.keyfile == NULL)
869 			smime_config.keyfile = smime_config.recipfile;
870 	} else if (smime_config.operation == SMIME_SIGN) {
871 		if (smime_config.keyfile == NULL)
872 			smime_config.keyfile = smime_config.signerfile;
873 	} else {
874 		smime_config.keyfile = NULL;
875 	}
876 
877 	if (smime_config.keyfile != NULL) {
878 		key = load_key(bio_err, smime_config.keyfile,
879 		    smime_config.keyform, 0, passin, "signing key file");
880 		if (key == NULL)
881 			goto end;
882 	}
883 	if (smime_config.infile != NULL) {
884 		if ((in = BIO_new_file(smime_config.infile, inmode)) == NULL) {
885 			BIO_printf(bio_err,
886 			    "Can't open input file %s\n", smime_config.infile);
887 			goto end;
888 		}
889 	} else {
890 		if ((in = BIO_new_fp(stdin, BIO_NOCLOSE)) == NULL)
891 			goto end;
892 	}
893 
894 	if (smime_config.operation & SMIME_IP) {
895 		if (smime_config.informat == FORMAT_SMIME)
896 			p7 = SMIME_read_PKCS7(in, &indata);
897 		else if (smime_config.informat == FORMAT_PEM)
898 			p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
899 		else if (smime_config.informat == FORMAT_ASN1)
900 			p7 = d2i_PKCS7_bio(in, NULL);
901 		else {
902 			BIO_printf(bio_err,
903 			    "Bad input format for PKCS#7 file\n");
904 			goto end;
905 		}
906 
907 		if (p7 == NULL) {
908 			BIO_printf(bio_err, "Error reading S/MIME message\n");
909 			goto end;
910 		}
911 		if (smime_config.contfile != NULL) {
912 			BIO_free(indata);
913 			if ((indata = BIO_new_file(smime_config.contfile,
914 			    "rb")) == NULL) {
915 				BIO_printf(bio_err,
916 				    "Can't read content file %s\n",
917 				    smime_config.contfile);
918 				goto end;
919 			}
920 		}
921 	}
922 	if (smime_config.outfile != NULL) {
923 		if ((out = BIO_new_file(smime_config.outfile, outmode)) == NULL) {
924 			BIO_printf(bio_err,
925 			    "Can't open output file %s\n",
926 			    smime_config.outfile);
927 			goto end;
928 		}
929 	} else {
930 		if ((out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL)
931 			goto end;
932 	}
933 
934 	if (smime_config.operation == SMIME_VERIFY) {
935 		if ((store = setup_verify(bio_err, smime_config.CAfile,
936 		    smime_config.CApath)) == NULL)
937 			goto end;
938 		X509_STORE_set_verify_cb(store, smime_cb);
939 		if (smime_config.vpm != NULL) {
940 			if (!X509_STORE_set1_param(store, smime_config.vpm))
941 				goto end;
942 		}
943 	}
944 	ret = 3;
945 
946 	if (smime_config.operation == SMIME_ENCRYPT) {
947 		if (smime_config.indef)
948 			smime_config.flags |= PKCS7_STREAM;
949 		p7 = PKCS7_encrypt(encerts, in, smime_config.cipher,
950 		    smime_config.flags);
951 	} else if (smime_config.operation & SMIME_SIGNERS) {
952 		int i;
953 		/*
954 		 * If detached data content we only enable streaming if
955 		 * S/MIME output format.
956 		 */
957 		if (smime_config.operation == SMIME_SIGN) {
958 			if (smime_config.flags & PKCS7_DETACHED) {
959 				if (smime_config.outformat == FORMAT_SMIME)
960 					smime_config.flags |= PKCS7_STREAM;
961 			} else if (smime_config.indef) {
962 				smime_config.flags |= PKCS7_STREAM;
963 			}
964 			smime_config.flags |= PKCS7_PARTIAL;
965 			p7 = PKCS7_sign(NULL, NULL, other, in,
966 			    smime_config.flags);
967 			if (p7 == NULL)
968 				goto end;
969 		} else {
970 			smime_config.flags |= PKCS7_REUSE_DIGEST;
971 		}
972 		for (i = 0; i < sk_OPENSSL_STRING_num(smime_config.sksigners); i++) {
973 			smime_config.signerfile =
974 			    sk_OPENSSL_STRING_value(smime_config.sksigners, i);
975 			smime_config.keyfile =
976 			    sk_OPENSSL_STRING_value(smime_config.skkeys, i);
977 			signer = load_cert(bio_err, smime_config.signerfile,
978 			    FORMAT_PEM, NULL, "signer certificate");
979 			if (signer == NULL)
980 				goto end;
981 			key = load_key(bio_err, smime_config.keyfile,
982 			    smime_config.keyform, 0, passin,
983 			    "signing key file");
984 			if (key == NULL)
985 				goto end;
986 			if (PKCS7_sign_add_signer(p7, signer, key,
987 			    smime_config.sign_md, smime_config.flags) == NULL)
988 				goto end;
989 			X509_free(signer);
990 			signer = NULL;
991 			EVP_PKEY_free(key);
992 			key = NULL;
993 		}
994 		/* If not streaming or resigning finalize structure */
995 		if ((smime_config.operation == SMIME_SIGN) &&
996 		    !(smime_config.flags & PKCS7_STREAM)) {
997 			if (!PKCS7_final(p7, in, smime_config.flags))
998 				goto end;
999 		}
1000 	}
1001 	if (p7 == NULL) {
1002 		BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
1003 		goto end;
1004 	}
1005 	ret = 4;
1006 
1007 	if (smime_config.operation == SMIME_DECRYPT) {
1008 		if (!PKCS7_decrypt(p7, key, recip, out, smime_config.flags)) {
1009 			BIO_printf(bio_err,
1010 			    "Error decrypting PKCS#7 structure\n");
1011 			goto end;
1012 		}
1013 	} else if (smime_config.operation == SMIME_VERIFY) {
1014 		STACK_OF(X509) *signers;
1015 		if (PKCS7_verify(p7, other, store, indata, out,
1016 		    smime_config.flags)) {
1017 			BIO_printf(bio_err, "Verification successful\n");
1018 		} else {
1019 			BIO_printf(bio_err, "Verification failure\n");
1020 			goto end;
1021 		}
1022 		if ((signers = PKCS7_get0_signers(p7, other,
1023 		    smime_config.flags)) == NULL)
1024 			goto end;
1025 		if (!save_certs(smime_config.signerfile, signers)) {
1026 			BIO_printf(bio_err, "Error writing signers to %s\n",
1027 			    smime_config.signerfile);
1028 			sk_X509_free(signers);
1029 			ret = 5;
1030 			goto end;
1031 		}
1032 		sk_X509_free(signers);
1033 	} else if (smime_config.operation == SMIME_PK7OUT) {
1034 		PEM_write_bio_PKCS7(out, p7);
1035 	} else {
1036 		if (smime_config.to != NULL)
1037 			BIO_printf(out, "To: %s\n", smime_config.to);
1038 		if (smime_config.from != NULL)
1039 			BIO_printf(out, "From: %s\n", smime_config.from);
1040 		if (smime_config.subject != NULL)
1041 			BIO_printf(out, "Subject: %s\n", smime_config.subject);
1042 		if (smime_config.outformat == FORMAT_SMIME) {
1043 			if (smime_config.operation == SMIME_RESIGN) {
1044 				if (!SMIME_write_PKCS7(out, p7, indata,
1045 				    smime_config.flags))
1046 					goto end;
1047 			} else {
1048 				if (!SMIME_write_PKCS7(out, p7, in,
1049 				    smime_config.flags))
1050 					goto end;
1051 			}
1052 		} else if (smime_config.outformat == FORMAT_PEM) {
1053 			if (!PEM_write_bio_PKCS7_stream(out, p7, in,
1054 			    smime_config.flags))
1055 				goto end;
1056 		} else if (smime_config.outformat == FORMAT_ASN1) {
1057 			if (!i2d_PKCS7_bio_stream(out, p7, in,
1058 			    smime_config.flags))
1059 				goto end;
1060 		} else {
1061 			BIO_printf(bio_err,
1062 			    "Bad output format for PKCS#7 file\n");
1063 			goto end;
1064 		}
1065 	}
1066 
1067 	ret = 0;
1068 
1069  end:
1070 	if (ret)
1071 		ERR_print_errors(bio_err);
1072 	sk_X509_pop_free(encerts, X509_free);
1073 	sk_X509_pop_free(other, X509_free);
1074 	X509_VERIFY_PARAM_free(smime_config.vpm);
1075 	sk_OPENSSL_STRING_free(smime_config.sksigners);
1076 	sk_OPENSSL_STRING_free(smime_config.skkeys);
1077 	X509_STORE_free(store);
1078 	X509_free(cert);
1079 	X509_free(recip);
1080 	X509_free(signer);
1081 	EVP_PKEY_free(key);
1082 	PKCS7_free(p7);
1083 	BIO_free(in);
1084 	BIO_free(indata);
1085 	BIO_free_all(out);
1086 	free(passin);
1087 
1088 	return (ret);
1089 }
1090 
1091 static int
1092 save_certs(char *signerfile, STACK_OF(X509) *signers)
1093 {
1094 	int i;
1095 	BIO *tmp;
1096 
1097 	if (signerfile == NULL)
1098 		return 1;
1099 	tmp = BIO_new_file(signerfile, "w");
1100 	if (tmp == NULL)
1101 		return 0;
1102 	for (i = 0; i < sk_X509_num(signers); i++)
1103 		PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
1104 	BIO_free(tmp);
1105 
1106 	return 1;
1107 }
1108 
1109 /* Minimal callback just to output policy info (if any) */
1110 static int
1111 smime_cb(int ok, X509_STORE_CTX *ctx)
1112 {
1113 	int error;
1114 
1115 	error = X509_STORE_CTX_get_error(ctx);
1116 
1117 	if ((error != X509_V_ERR_NO_EXPLICIT_POLICY) &&
1118 	    ((error != X509_V_OK) || (ok != 2)))
1119 		return ok;
1120 
1121 	policies_print(NULL, ctx);
1122 
1123 	return ok;
1124 }
1125