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