xref: /openbsd-src/usr.bin/openssl/smime.c (revision 3374c67d44f9b75b98444cbf63020f777792342e)
1 /* $OpenBSD: smime.c,v 1.18 2022/11/11 17:07:39 joshua 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 (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
726 		perror("pledge");
727 		exit(1);
728 	}
729 
730 	memset(&smime_config, 0, sizeof(smime_config));
731 	smime_config.flags = PKCS7_DETACHED;
732 	smime_config.informat = FORMAT_SMIME;
733 	smime_config.outformat = FORMAT_SMIME;
734 	smime_config.keyform = FORMAT_PEM;
735 	if (options_parse(argc, argv, smime_options, NULL, &argsused) != 0) {
736 		goto argerr;
737 	}
738 	args = argv + argsused;
739 	ret = 1;
740 
741 	if (!(smime_config.operation & SMIME_SIGNERS) &&
742 	    (smime_config.skkeys != NULL || smime_config.sksigners != NULL)) {
743 		BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
744 		goto argerr;
745 	}
746 	if (smime_config.operation & SMIME_SIGNERS) {
747 		/* Check to see if any final signer needs to be appended */
748 		if (smime_config.keyfile != NULL &&
749 		    smime_config.signerfile == NULL) {
750 			BIO_puts(bio_err, "Illegal -inkey without -signer\n");
751 			goto argerr;
752 		}
753 		if (smime_config.signerfile != NULL) {
754 			if (smime_config.sksigners == NULL) {
755 				if ((smime_config.sksigners =
756 				    sk_OPENSSL_STRING_new_null()) == NULL)
757 					goto end;
758 			}
759 			if (!sk_OPENSSL_STRING_push(smime_config.sksigners,
760 			    smime_config.signerfile))
761 				goto end;
762 			if (smime_config.skkeys == NULL) {
763 				if ((smime_config.skkeys =
764 				    sk_OPENSSL_STRING_new_null()) == NULL)
765 					goto end;
766 			}
767 			if (smime_config.keyfile == NULL)
768 				smime_config.keyfile = smime_config.signerfile;
769 			if (!sk_OPENSSL_STRING_push(smime_config.skkeys,
770 			    smime_config.keyfile))
771 				goto end;
772 		}
773 		if (smime_config.sksigners == NULL) {
774 			BIO_printf(bio_err,
775 			    "No signer certificate specified\n");
776 			badarg = 1;
777 		}
778 		smime_config.signerfile = NULL;
779 		smime_config.keyfile = NULL;
780 	} else if (smime_config.operation == SMIME_DECRYPT) {
781 		if (smime_config.recipfile == NULL &&
782 		    smime_config.keyfile == NULL) {
783 			BIO_printf(bio_err,
784 			    "No recipient certificate or key specified\n");
785 			badarg = 1;
786 		}
787 	} else if (smime_config.operation == SMIME_ENCRYPT) {
788 		if (*args == NULL) {
789 			BIO_printf(bio_err,
790 			    "No recipient(s) certificate(s) specified\n");
791 			badarg = 1;
792 		}
793 	} else if (!smime_config.operation) {
794 		badarg = 1;
795 	}
796 
797 	if (badarg) {
798  argerr:
799 		smime_usage();
800 		goto end;
801 	}
802 
803 	if (!app_passwd(bio_err, smime_config.passargin, NULL, &passin, NULL)) {
804 		BIO_printf(bio_err, "Error getting password\n");
805 		goto end;
806 	}
807 	ret = 2;
808 
809 	if (!(smime_config.operation & SMIME_SIGNERS))
810 		smime_config.flags &= ~PKCS7_DETACHED;
811 
812 	if (smime_config.operation & SMIME_OP) {
813 		if (smime_config.outformat == FORMAT_ASN1)
814 			outmode = "wb";
815 	} else {
816 		if (smime_config.flags & PKCS7_BINARY)
817 			outmode = "wb";
818 	}
819 
820 	if (smime_config.operation & SMIME_IP) {
821 		if (smime_config.informat == FORMAT_ASN1)
822 			inmode = "rb";
823 	} else {
824 		if (smime_config.flags & PKCS7_BINARY)
825 			inmode = "rb";
826 	}
827 
828 	if (smime_config.operation == SMIME_ENCRYPT) {
829 		if (smime_config.cipher == NULL) {
830 #ifndef OPENSSL_NO_RC2
831 			smime_config.cipher = EVP_rc2_40_cbc();
832 #else
833 			BIO_printf(bio_err, "No cipher selected\n");
834 			goto end;
835 #endif
836 		}
837 		if ((encerts = sk_X509_new_null()) == NULL)
838 			goto end;
839 		while (*args != NULL) {
840 			if ((cert = load_cert(bio_err, *args, FORMAT_PEM,
841 			    NULL, "recipient certificate file")) == NULL) {
842 				goto end;
843 			}
844 			if (!sk_X509_push(encerts, cert))
845 				goto end;
846 			cert = NULL;
847 			args++;
848 		}
849 	}
850 	if (smime_config.certfile != NULL) {
851 		if ((other = load_certs(bio_err, smime_config.certfile,
852 		    FORMAT_PEM, NULL, "certificate file")) == NULL) {
853 			ERR_print_errors(bio_err);
854 			goto end;
855 		}
856 	}
857 	if (smime_config.recipfile != NULL &&
858 	    (smime_config.operation == SMIME_DECRYPT)) {
859 		if ((recip = load_cert(bio_err, smime_config.recipfile,
860 		    FORMAT_PEM, NULL, "recipient certificate file")) == NULL) {
861 			ERR_print_errors(bio_err);
862 			goto end;
863 		}
864 	}
865 	if (smime_config.operation == SMIME_DECRYPT) {
866 		if (smime_config.keyfile == NULL)
867 			smime_config.keyfile = smime_config.recipfile;
868 	} else if (smime_config.operation == SMIME_SIGN) {
869 		if (smime_config.keyfile == NULL)
870 			smime_config.keyfile = smime_config.signerfile;
871 	} else {
872 		smime_config.keyfile = NULL;
873 	}
874 
875 	if (smime_config.keyfile != NULL) {
876 		key = load_key(bio_err, smime_config.keyfile,
877 		    smime_config.keyform, 0, passin, "signing key file");
878 		if (key == NULL)
879 			goto end;
880 	}
881 	if (smime_config.infile != NULL) {
882 		if ((in = BIO_new_file(smime_config.infile, inmode)) == NULL) {
883 			BIO_printf(bio_err,
884 			    "Can't open input file %s\n", smime_config.infile);
885 			goto end;
886 		}
887 	} else {
888 		if ((in = BIO_new_fp(stdin, BIO_NOCLOSE)) == NULL)
889 			goto end;
890 	}
891 
892 	if (smime_config.operation & SMIME_IP) {
893 		if (smime_config.informat == FORMAT_SMIME)
894 			p7 = SMIME_read_PKCS7(in, &indata);
895 		else if (smime_config.informat == FORMAT_PEM)
896 			p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
897 		else if (smime_config.informat == FORMAT_ASN1)
898 			p7 = d2i_PKCS7_bio(in, NULL);
899 		else {
900 			BIO_printf(bio_err,
901 			    "Bad input format for PKCS#7 file\n");
902 			goto end;
903 		}
904 
905 		if (p7 == NULL) {
906 			BIO_printf(bio_err, "Error reading S/MIME message\n");
907 			goto end;
908 		}
909 		if (smime_config.contfile != NULL) {
910 			BIO_free(indata);
911 			if ((indata = BIO_new_file(smime_config.contfile,
912 			    "rb")) == NULL) {
913 				BIO_printf(bio_err,
914 				    "Can't read content file %s\n",
915 				    smime_config.contfile);
916 				goto end;
917 			}
918 		}
919 	}
920 	if (smime_config.outfile != NULL) {
921 		if ((out = BIO_new_file(smime_config.outfile, outmode)) == NULL) {
922 			BIO_printf(bio_err,
923 			    "Can't open output file %s\n",
924 			    smime_config.outfile);
925 			goto end;
926 		}
927 	} else {
928 		if ((out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL)
929 			goto end;
930 	}
931 
932 	if (smime_config.operation == SMIME_VERIFY) {
933 		if ((store = setup_verify(bio_err, smime_config.CAfile,
934 		    smime_config.CApath)) == NULL)
935 			goto end;
936 		X509_STORE_set_verify_cb(store, smime_cb);
937 		if (smime_config.vpm != NULL) {
938 			if (!X509_STORE_set1_param(store, smime_config.vpm))
939 				goto end;
940 		}
941 	}
942 	ret = 3;
943 
944 	if (smime_config.operation == SMIME_ENCRYPT) {
945 		if (smime_config.indef)
946 			smime_config.flags |= PKCS7_STREAM;
947 		p7 = PKCS7_encrypt(encerts, in, smime_config.cipher,
948 		    smime_config.flags);
949 	} else if (smime_config.operation & SMIME_SIGNERS) {
950 		int i;
951 		/*
952 		 * If detached data content we only enable streaming if
953 		 * S/MIME output format.
954 		 */
955 		if (smime_config.operation == SMIME_SIGN) {
956 			if (smime_config.flags & PKCS7_DETACHED) {
957 				if (smime_config.outformat == FORMAT_SMIME)
958 					smime_config.flags |= PKCS7_STREAM;
959 			} else if (smime_config.indef) {
960 				smime_config.flags |= PKCS7_STREAM;
961 			}
962 			smime_config.flags |= PKCS7_PARTIAL;
963 			p7 = PKCS7_sign(NULL, NULL, other, in,
964 			    smime_config.flags);
965 			if (p7 == NULL)
966 				goto end;
967 		} else {
968 			smime_config.flags |= PKCS7_REUSE_DIGEST;
969 		}
970 		for (i = 0; i < sk_OPENSSL_STRING_num(smime_config.sksigners); i++) {
971 			smime_config.signerfile =
972 			    sk_OPENSSL_STRING_value(smime_config.sksigners, i);
973 			smime_config.keyfile =
974 			    sk_OPENSSL_STRING_value(smime_config.skkeys, i);
975 			signer = load_cert(bio_err, smime_config.signerfile,
976 			    FORMAT_PEM, NULL, "signer certificate");
977 			if (signer == NULL)
978 				goto end;
979 			key = load_key(bio_err, smime_config.keyfile,
980 			    smime_config.keyform, 0, passin,
981 			    "signing key file");
982 			if (key == NULL)
983 				goto end;
984 			if (PKCS7_sign_add_signer(p7, signer, key,
985 			    smime_config.sign_md, smime_config.flags) == NULL)
986 				goto end;
987 			X509_free(signer);
988 			signer = NULL;
989 			EVP_PKEY_free(key);
990 			key = NULL;
991 		}
992 		/* If not streaming or resigning finalize structure */
993 		if ((smime_config.operation == SMIME_SIGN) &&
994 		    !(smime_config.flags & PKCS7_STREAM)) {
995 			if (!PKCS7_final(p7, in, smime_config.flags))
996 				goto end;
997 		}
998 	}
999 	if (p7 == NULL) {
1000 		BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
1001 		goto end;
1002 	}
1003 	ret = 4;
1004 
1005 	if (smime_config.operation == SMIME_DECRYPT) {
1006 		if (!PKCS7_decrypt(p7, key, recip, out, smime_config.flags)) {
1007 			BIO_printf(bio_err,
1008 			    "Error decrypting PKCS#7 structure\n");
1009 			goto end;
1010 		}
1011 	} else if (smime_config.operation == SMIME_VERIFY) {
1012 		STACK_OF(X509) *signers;
1013 		if (PKCS7_verify(p7, other, store, indata, out,
1014 		    smime_config.flags)) {
1015 			BIO_printf(bio_err, "Verification successful\n");
1016 		} else {
1017 			BIO_printf(bio_err, "Verification failure\n");
1018 			goto end;
1019 		}
1020 		if ((signers = PKCS7_get0_signers(p7, other,
1021 		    smime_config.flags)) == NULL)
1022 			goto end;
1023 		if (!save_certs(smime_config.signerfile, signers)) {
1024 			BIO_printf(bio_err, "Error writing signers to %s\n",
1025 			    smime_config.signerfile);
1026 			sk_X509_free(signers);
1027 			ret = 5;
1028 			goto end;
1029 		}
1030 		sk_X509_free(signers);
1031 	} else if (smime_config.operation == SMIME_PK7OUT) {
1032 		PEM_write_bio_PKCS7(out, p7);
1033 	} else {
1034 		if (smime_config.to != NULL)
1035 			BIO_printf(out, "To: %s\n", smime_config.to);
1036 		if (smime_config.from != NULL)
1037 			BIO_printf(out, "From: %s\n", smime_config.from);
1038 		if (smime_config.subject != NULL)
1039 			BIO_printf(out, "Subject: %s\n", smime_config.subject);
1040 		if (smime_config.outformat == FORMAT_SMIME) {
1041 			if (smime_config.operation == SMIME_RESIGN) {
1042 				if (!SMIME_write_PKCS7(out, p7, indata,
1043 				    smime_config.flags))
1044 					goto end;
1045 			} else {
1046 				if (!SMIME_write_PKCS7(out, p7, in,
1047 				    smime_config.flags))
1048 					goto end;
1049 			}
1050 		} else if (smime_config.outformat == FORMAT_PEM) {
1051 			if (!PEM_write_bio_PKCS7_stream(out, p7, in,
1052 			    smime_config.flags))
1053 				goto end;
1054 		} else if (smime_config.outformat == FORMAT_ASN1) {
1055 			if (!i2d_PKCS7_bio_stream(out, p7, in,
1056 			    smime_config.flags))
1057 				goto end;
1058 		} else {
1059 			BIO_printf(bio_err,
1060 			    "Bad output format for PKCS#7 file\n");
1061 			goto end;
1062 		}
1063 	}
1064 
1065 	ret = 0;
1066 
1067  end:
1068 	if (ret)
1069 		ERR_print_errors(bio_err);
1070 	sk_X509_pop_free(encerts, X509_free);
1071 	sk_X509_pop_free(other, X509_free);
1072 	X509_VERIFY_PARAM_free(smime_config.vpm);
1073 	sk_OPENSSL_STRING_free(smime_config.sksigners);
1074 	sk_OPENSSL_STRING_free(smime_config.skkeys);
1075 	X509_STORE_free(store);
1076 	X509_free(cert);
1077 	X509_free(recip);
1078 	X509_free(signer);
1079 	EVP_PKEY_free(key);
1080 	PKCS7_free(p7);
1081 	BIO_free(in);
1082 	BIO_free(indata);
1083 	BIO_free_all(out);
1084 	free(passin);
1085 
1086 	return (ret);
1087 }
1088 
1089 static int
1090 save_certs(char *signerfile, STACK_OF(X509) *signers)
1091 {
1092 	int i;
1093 	BIO *tmp;
1094 
1095 	if (signerfile == NULL)
1096 		return 1;
1097 	tmp = BIO_new_file(signerfile, "w");
1098 	if (tmp == NULL)
1099 		return 0;
1100 	for (i = 0; i < sk_X509_num(signers); i++)
1101 		PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
1102 	BIO_free(tmp);
1103 
1104 	return 1;
1105 }
1106 
1107 /* Minimal callback just to output policy info (if any) */
1108 static int
1109 smime_cb(int ok, X509_STORE_CTX *ctx)
1110 {
1111 	int error;
1112 
1113 	error = X509_STORE_CTX_get_error(ctx);
1114 
1115 	if ((error != X509_V_ERR_NO_EXPLICIT_POLICY) &&
1116 	    ((error != X509_V_OK) || (ok != 2)))
1117 		return ok;
1118 
1119 	policies_print(NULL, ctx);
1120 
1121 	return ok;
1122 }
1123