1 /* $OpenBSD: smime.c,v 1.17 2022/01/16 07:12:28 inoguchi Exp $ */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3 * project.
4 */
5 /* ====================================================================
6 * Copyright (c) 1999-2004 The OpenSSL Project. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. All advertising materials mentioning features or use of this
21 * software must display the following acknowledgment:
22 * "This product includes software developed by the OpenSSL Project
23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24 *
25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26 * endorse or promote products derived from this software without
27 * prior written permission. For written permission, please contact
28 * licensing@OpenSSL.org.
29 *
30 * 5. Products derived from this software may not be called "OpenSSL"
31 * nor may "OpenSSL" appear in their names without prior written
32 * permission of the OpenSSL Project.
33 *
34 * 6. Redistributions of any form whatsoever must retain the following
35 * acknowledgment:
36 * "This product includes software developed by the OpenSSL Project
37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50 * OF THE POSSIBILITY OF SUCH DAMAGE.
51 * ====================================================================
52 *
53 * This product includes cryptographic software written by Eric Young
54 * (eay@cryptsoft.com). This product includes software written by Tim
55 * Hudson (tjh@cryptsoft.com).
56 *
57 */
58
59 /* S/MIME utility function */
60
61 #include <stdio.h>
62 #include <string.h>
63
64 #include "apps.h"
65
66 #include <openssl/crypto.h>
67 #include <openssl/err.h>
68 #include <openssl/pem.h>
69 #include <openssl/x509_vfy.h>
70 #include <openssl/x509v3.h>
71
72 static int save_certs(char *signerfile, STACK_OF(X509) *signers);
73 static int smime_cb(int ok, X509_STORE_CTX *ctx);
74
75 #define SMIME_OP 0x10
76 #define SMIME_IP 0x20
77 #define SMIME_SIGNERS 0x40
78 #define SMIME_ENCRYPT (1 | SMIME_OP)
79 #define SMIME_DECRYPT (2 | SMIME_IP)
80 #define SMIME_SIGN (3 | SMIME_OP | SMIME_SIGNERS)
81 #define SMIME_VERIFY (4 | SMIME_IP)
82 #define SMIME_PK7OUT (5 | SMIME_IP | SMIME_OP)
83 #define SMIME_RESIGN (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
84
85 static struct {
86 char *CAfile;
87 char *CApath;
88 char *certfile;
89 const EVP_CIPHER *cipher;
90 char *contfile;
91 int flags;
92 char *from;
93 int indef;
94 char *infile;
95 int informat;
96 char *keyfile;
97 int keyform;
98 int operation;
99 char *outfile;
100 int outformat;
101 char *passargin;
102 char *recipfile;
103 const EVP_MD *sign_md;
104 char *signerfile;
105 STACK_OF(OPENSSL_STRING) *skkeys;
106 STACK_OF(OPENSSL_STRING) *sksigners;
107 char *subject;
108 char *to;
109 X509_VERIFY_PARAM *vpm;
110 } smime_config;
111
112 static const EVP_CIPHER *
get_cipher_by_name(char * name)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
smime_opt_cipher(int argc,char ** argv,int * argsused)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
smime_opt_inkey(char * arg)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
smime_opt_md(char * arg)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
smime_opt_signer(char * arg)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
smime_opt_verify_param(int argc,char ** argv,int * argsused)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
smime_usage(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
smime_main(int argc,char ** argv)710 smime_main(int argc, char **argv)
711 {
712 int ret = 0;
713 char **args;
714 int argsused = 0;
715 const char *inmode = "r", *outmode = "w";
716 PKCS7 *p7 = NULL;
717 X509_STORE *store = NULL;
718 X509 *cert = NULL, *recip = NULL, *signer = NULL;
719 EVP_PKEY *key = NULL;
720 STACK_OF(X509) *encerts = NULL, *other = NULL;
721 BIO *in = NULL, *out = NULL, *indata = NULL;
722 int badarg = 0;
723 char *passin = NULL;
724
725 if (single_execution) {
726 if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
727 perror("pledge");
728 exit(1);
729 }
730 }
731
732 memset(&smime_config, 0, sizeof(smime_config));
733 smime_config.flags = PKCS7_DETACHED;
734 smime_config.informat = FORMAT_SMIME;
735 smime_config.outformat = FORMAT_SMIME;
736 smime_config.keyform = FORMAT_PEM;
737 if (options_parse(argc, argv, smime_options, NULL, &argsused) != 0) {
738 goto argerr;
739 }
740 args = argv + argsused;
741 ret = 1;
742
743 if (!(smime_config.operation & SMIME_SIGNERS) &&
744 (smime_config.skkeys != NULL || smime_config.sksigners != NULL)) {
745 BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
746 goto argerr;
747 }
748 if (smime_config.operation & SMIME_SIGNERS) {
749 /* Check to see if any final signer needs to be appended */
750 if (smime_config.keyfile != NULL &&
751 smime_config.signerfile == NULL) {
752 BIO_puts(bio_err, "Illegal -inkey without -signer\n");
753 goto argerr;
754 }
755 if (smime_config.signerfile != NULL) {
756 if (smime_config.sksigners == NULL) {
757 if ((smime_config.sksigners =
758 sk_OPENSSL_STRING_new_null()) == NULL)
759 goto end;
760 }
761 if (!sk_OPENSSL_STRING_push(smime_config.sksigners,
762 smime_config.signerfile))
763 goto end;
764 if (smime_config.skkeys == NULL) {
765 if ((smime_config.skkeys =
766 sk_OPENSSL_STRING_new_null()) == NULL)
767 goto end;
768 }
769 if (smime_config.keyfile == NULL)
770 smime_config.keyfile = smime_config.signerfile;
771 if (!sk_OPENSSL_STRING_push(smime_config.skkeys,
772 smime_config.keyfile))
773 goto end;
774 }
775 if (smime_config.sksigners == NULL) {
776 BIO_printf(bio_err,
777 "No signer certificate specified\n");
778 badarg = 1;
779 }
780 smime_config.signerfile = NULL;
781 smime_config.keyfile = NULL;
782 } else if (smime_config.operation == SMIME_DECRYPT) {
783 if (smime_config.recipfile == NULL &&
784 smime_config.keyfile == NULL) {
785 BIO_printf(bio_err,
786 "No recipient certificate or key specified\n");
787 badarg = 1;
788 }
789 } else if (smime_config.operation == SMIME_ENCRYPT) {
790 if (*args == NULL) {
791 BIO_printf(bio_err,
792 "No recipient(s) certificate(s) specified\n");
793 badarg = 1;
794 }
795 } else if (!smime_config.operation) {
796 badarg = 1;
797 }
798
799 if (badarg) {
800 argerr:
801 smime_usage();
802 goto end;
803 }
804
805 if (!app_passwd(bio_err, smime_config.passargin, NULL, &passin, NULL)) {
806 BIO_printf(bio_err, "Error getting password\n");
807 goto end;
808 }
809 ret = 2;
810
811 if (!(smime_config.operation & SMIME_SIGNERS))
812 smime_config.flags &= ~PKCS7_DETACHED;
813
814 if (smime_config.operation & SMIME_OP) {
815 if (smime_config.outformat == FORMAT_ASN1)
816 outmode = "wb";
817 } else {
818 if (smime_config.flags & PKCS7_BINARY)
819 outmode = "wb";
820 }
821
822 if (smime_config.operation & SMIME_IP) {
823 if (smime_config.informat == FORMAT_ASN1)
824 inmode = "rb";
825 } else {
826 if (smime_config.flags & PKCS7_BINARY)
827 inmode = "rb";
828 }
829
830 if (smime_config.operation == SMIME_ENCRYPT) {
831 if (smime_config.cipher == NULL) {
832 #ifndef OPENSSL_NO_RC2
833 smime_config.cipher = EVP_rc2_40_cbc();
834 #else
835 BIO_printf(bio_err, "No cipher selected\n");
836 goto end;
837 #endif
838 }
839 if ((encerts = sk_X509_new_null()) == NULL)
840 goto end;
841 while (*args != NULL) {
842 if ((cert = load_cert(bio_err, *args, FORMAT_PEM,
843 NULL, "recipient certificate file")) == NULL) {
844 goto end;
845 }
846 if (!sk_X509_push(encerts, cert))
847 goto end;
848 cert = NULL;
849 args++;
850 }
851 }
852 if (smime_config.certfile != NULL) {
853 if ((other = load_certs(bio_err, smime_config.certfile,
854 FORMAT_PEM, NULL, "certificate file")) == NULL) {
855 ERR_print_errors(bio_err);
856 goto end;
857 }
858 }
859 if (smime_config.recipfile != NULL &&
860 (smime_config.operation == SMIME_DECRYPT)) {
861 if ((recip = load_cert(bio_err, smime_config.recipfile,
862 FORMAT_PEM, NULL, "recipient certificate file")) == NULL) {
863 ERR_print_errors(bio_err);
864 goto end;
865 }
866 }
867 if (smime_config.operation == SMIME_DECRYPT) {
868 if (smime_config.keyfile == NULL)
869 smime_config.keyfile = smime_config.recipfile;
870 } else if (smime_config.operation == SMIME_SIGN) {
871 if (smime_config.keyfile == NULL)
872 smime_config.keyfile = smime_config.signerfile;
873 } else {
874 smime_config.keyfile = NULL;
875 }
876
877 if (smime_config.keyfile != NULL) {
878 key = load_key(bio_err, smime_config.keyfile,
879 smime_config.keyform, 0, passin, "signing key file");
880 if (key == NULL)
881 goto end;
882 }
883 if (smime_config.infile != NULL) {
884 if ((in = BIO_new_file(smime_config.infile, inmode)) == NULL) {
885 BIO_printf(bio_err,
886 "Can't open input file %s\n", smime_config.infile);
887 goto end;
888 }
889 } else {
890 if ((in = BIO_new_fp(stdin, BIO_NOCLOSE)) == NULL)
891 goto end;
892 }
893
894 if (smime_config.operation & SMIME_IP) {
895 if (smime_config.informat == FORMAT_SMIME)
896 p7 = SMIME_read_PKCS7(in, &indata);
897 else if (smime_config.informat == FORMAT_PEM)
898 p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
899 else if (smime_config.informat == FORMAT_ASN1)
900 p7 = d2i_PKCS7_bio(in, NULL);
901 else {
902 BIO_printf(bio_err,
903 "Bad input format for PKCS#7 file\n");
904 goto end;
905 }
906
907 if (p7 == NULL) {
908 BIO_printf(bio_err, "Error reading S/MIME message\n");
909 goto end;
910 }
911 if (smime_config.contfile != NULL) {
912 BIO_free(indata);
913 if ((indata = BIO_new_file(smime_config.contfile,
914 "rb")) == NULL) {
915 BIO_printf(bio_err,
916 "Can't read content file %s\n",
917 smime_config.contfile);
918 goto end;
919 }
920 }
921 }
922 if (smime_config.outfile != NULL) {
923 if ((out = BIO_new_file(smime_config.outfile, outmode)) == NULL) {
924 BIO_printf(bio_err,
925 "Can't open output file %s\n",
926 smime_config.outfile);
927 goto end;
928 }
929 } else {
930 if ((out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL)
931 goto end;
932 }
933
934 if (smime_config.operation == SMIME_VERIFY) {
935 if ((store = setup_verify(bio_err, smime_config.CAfile,
936 smime_config.CApath)) == NULL)
937 goto end;
938 X509_STORE_set_verify_cb(store, smime_cb);
939 if (smime_config.vpm != NULL) {
940 if (!X509_STORE_set1_param(store, smime_config.vpm))
941 goto end;
942 }
943 }
944 ret = 3;
945
946 if (smime_config.operation == SMIME_ENCRYPT) {
947 if (smime_config.indef)
948 smime_config.flags |= PKCS7_STREAM;
949 p7 = PKCS7_encrypt(encerts, in, smime_config.cipher,
950 smime_config.flags);
951 } else if (smime_config.operation & SMIME_SIGNERS) {
952 int i;
953 /*
954 * If detached data content we only enable streaming if
955 * S/MIME output format.
956 */
957 if (smime_config.operation == SMIME_SIGN) {
958 if (smime_config.flags & PKCS7_DETACHED) {
959 if (smime_config.outformat == FORMAT_SMIME)
960 smime_config.flags |= PKCS7_STREAM;
961 } else if (smime_config.indef) {
962 smime_config.flags |= PKCS7_STREAM;
963 }
964 smime_config.flags |= PKCS7_PARTIAL;
965 p7 = PKCS7_sign(NULL, NULL, other, in,
966 smime_config.flags);
967 if (p7 == NULL)
968 goto end;
969 } else {
970 smime_config.flags |= PKCS7_REUSE_DIGEST;
971 }
972 for (i = 0; i < sk_OPENSSL_STRING_num(smime_config.sksigners); i++) {
973 smime_config.signerfile =
974 sk_OPENSSL_STRING_value(smime_config.sksigners, i);
975 smime_config.keyfile =
976 sk_OPENSSL_STRING_value(smime_config.skkeys, i);
977 signer = load_cert(bio_err, smime_config.signerfile,
978 FORMAT_PEM, NULL, "signer certificate");
979 if (signer == NULL)
980 goto end;
981 key = load_key(bio_err, smime_config.keyfile,
982 smime_config.keyform, 0, passin,
983 "signing key file");
984 if (key == NULL)
985 goto end;
986 if (PKCS7_sign_add_signer(p7, signer, key,
987 smime_config.sign_md, smime_config.flags) == NULL)
988 goto end;
989 X509_free(signer);
990 signer = NULL;
991 EVP_PKEY_free(key);
992 key = NULL;
993 }
994 /* If not streaming or resigning finalize structure */
995 if ((smime_config.operation == SMIME_SIGN) &&
996 !(smime_config.flags & PKCS7_STREAM)) {
997 if (!PKCS7_final(p7, in, smime_config.flags))
998 goto end;
999 }
1000 }
1001 if (p7 == NULL) {
1002 BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
1003 goto end;
1004 }
1005 ret = 4;
1006
1007 if (smime_config.operation == SMIME_DECRYPT) {
1008 if (!PKCS7_decrypt(p7, key, recip, out, smime_config.flags)) {
1009 BIO_printf(bio_err,
1010 "Error decrypting PKCS#7 structure\n");
1011 goto end;
1012 }
1013 } else if (smime_config.operation == SMIME_VERIFY) {
1014 STACK_OF(X509) *signers;
1015 if (PKCS7_verify(p7, other, store, indata, out,
1016 smime_config.flags)) {
1017 BIO_printf(bio_err, "Verification successful\n");
1018 } else {
1019 BIO_printf(bio_err, "Verification failure\n");
1020 goto end;
1021 }
1022 if ((signers = PKCS7_get0_signers(p7, other,
1023 smime_config.flags)) == NULL)
1024 goto end;
1025 if (!save_certs(smime_config.signerfile, signers)) {
1026 BIO_printf(bio_err, "Error writing signers to %s\n",
1027 smime_config.signerfile);
1028 sk_X509_free(signers);
1029 ret = 5;
1030 goto end;
1031 }
1032 sk_X509_free(signers);
1033 } else if (smime_config.operation == SMIME_PK7OUT) {
1034 PEM_write_bio_PKCS7(out, p7);
1035 } else {
1036 if (smime_config.to != NULL)
1037 BIO_printf(out, "To: %s\n", smime_config.to);
1038 if (smime_config.from != NULL)
1039 BIO_printf(out, "From: %s\n", smime_config.from);
1040 if (smime_config.subject != NULL)
1041 BIO_printf(out, "Subject: %s\n", smime_config.subject);
1042 if (smime_config.outformat == FORMAT_SMIME) {
1043 if (smime_config.operation == SMIME_RESIGN) {
1044 if (!SMIME_write_PKCS7(out, p7, indata,
1045 smime_config.flags))
1046 goto end;
1047 } else {
1048 if (!SMIME_write_PKCS7(out, p7, in,
1049 smime_config.flags))
1050 goto end;
1051 }
1052 } else if (smime_config.outformat == FORMAT_PEM) {
1053 if (!PEM_write_bio_PKCS7_stream(out, p7, in,
1054 smime_config.flags))
1055 goto end;
1056 } else if (smime_config.outformat == FORMAT_ASN1) {
1057 if (!i2d_PKCS7_bio_stream(out, p7, in,
1058 smime_config.flags))
1059 goto end;
1060 } else {
1061 BIO_printf(bio_err,
1062 "Bad output format for PKCS#7 file\n");
1063 goto end;
1064 }
1065 }
1066
1067 ret = 0;
1068
1069 end:
1070 if (ret)
1071 ERR_print_errors(bio_err);
1072 sk_X509_pop_free(encerts, X509_free);
1073 sk_X509_pop_free(other, X509_free);
1074 X509_VERIFY_PARAM_free(smime_config.vpm);
1075 sk_OPENSSL_STRING_free(smime_config.sksigners);
1076 sk_OPENSSL_STRING_free(smime_config.skkeys);
1077 X509_STORE_free(store);
1078 X509_free(cert);
1079 X509_free(recip);
1080 X509_free(signer);
1081 EVP_PKEY_free(key);
1082 PKCS7_free(p7);
1083 BIO_free(in);
1084 BIO_free(indata);
1085 BIO_free_all(out);
1086 free(passin);
1087
1088 return (ret);
1089 }
1090
1091 static int
save_certs(char * signerfile,STACK_OF (X509)* signers)1092 save_certs(char *signerfile, STACK_OF(X509) *signers)
1093 {
1094 int i;
1095 BIO *tmp;
1096
1097 if (signerfile == NULL)
1098 return 1;
1099 tmp = BIO_new_file(signerfile, "w");
1100 if (tmp == NULL)
1101 return 0;
1102 for (i = 0; i < sk_X509_num(signers); i++)
1103 PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
1104 BIO_free(tmp);
1105
1106 return 1;
1107 }
1108
1109 /* Minimal callback just to output policy info (if any) */
1110 static int
smime_cb(int ok,X509_STORE_CTX * ctx)1111 smime_cb(int ok, X509_STORE_CTX *ctx)
1112 {
1113 int error;
1114
1115 error = X509_STORE_CTX_get_error(ctx);
1116
1117 if ((error != X509_V_ERR_NO_EXPLICIT_POLICY) &&
1118 ((error != X509_V_OK) || (ok != 2)))
1119 return ok;
1120
1121 policies_print(NULL, ctx);
1122
1123 return ok;
1124 }
1125