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