smime.c revision 296341
1/* smime.c */
2/*
3 * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4 * project.
5 */
6/* ====================================================================
7 * Copyright (c) 1999-2004 The OpenSSL Project.  All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in
18 *    the documentation and/or other materials provided with the
19 *    distribution.
20 *
21 * 3. All advertising materials mentioning features or use of this
22 *    software must display the following acknowledgment:
23 *    "This product includes software developed by the OpenSSL Project
24 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25 *
26 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 *    endorse or promote products derived from this software without
28 *    prior written permission. For written permission, please contact
29 *    licensing@OpenSSL.org.
30 *
31 * 5. Products derived from this software may not be called "OpenSSL"
32 *    nor may "OpenSSL" appear in their names without prior written
33 *    permission of the OpenSSL Project.
34 *
35 * 6. Redistributions of any form whatsoever must retain the following
36 *    acknowledgment:
37 *    "This product includes software developed by the OpenSSL Project
38 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 * OF THE POSSIBILITY OF SUCH DAMAGE.
52 * ====================================================================
53 *
54 * This product includes cryptographic software written by Eric Young
55 * (eay@cryptsoft.com).  This product includes software written by Tim
56 * Hudson (tjh@cryptsoft.com).
57 *
58 */
59
60/* S/MIME utility function */
61
62#include <stdio.h>
63#include <string.h>
64#include "apps.h"
65#include <openssl/crypto.h>
66#include <openssl/pem.h>
67#include <openssl/err.h>
68#include <openssl/x509_vfy.h>
69#include <openssl/x509v3.h>
70
71#undef PROG
72#define PROG smime_main
73static int save_certs(char *signerfile, STACK_OF(X509) *signers);
74static int smime_cb(int ok, X509_STORE_CTX *ctx);
75
76#define SMIME_OP        0x10
77#define SMIME_IP        0x20
78#define SMIME_SIGNERS   0x40
79#define SMIME_ENCRYPT   (1 | SMIME_OP)
80#define SMIME_DECRYPT   (2 | SMIME_IP)
81#define SMIME_SIGN      (3 | SMIME_OP | SMIME_SIGNERS)
82#define SMIME_VERIFY    (4 | SMIME_IP)
83#define SMIME_PK7OUT    (5 | SMIME_IP | SMIME_OP)
84#define SMIME_RESIGN    (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
85
86int MAIN(int, char **);
87
88int MAIN(int argc, char **argv)
89{
90    ENGINE *e = NULL;
91    int operation = 0;
92    int ret = 0;
93    char **args;
94    const char *inmode = "r", *outmode = "w";
95    char *infile = NULL, *outfile = NULL;
96    char *signerfile = NULL, *recipfile = NULL;
97    STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL;
98    char *certfile = NULL, *keyfile = NULL, *contfile = NULL;
99    const EVP_CIPHER *cipher = NULL;
100    PKCS7 *p7 = NULL;
101    X509_STORE *store = NULL;
102    X509 *cert = NULL, *recip = NULL, *signer = NULL;
103    EVP_PKEY *key = NULL;
104    STACK_OF(X509) *encerts = NULL, *other = NULL;
105    BIO *in = NULL, *out = NULL, *indata = NULL;
106    int badarg = 0;
107    int flags = PKCS7_DETACHED;
108    char *to = NULL, *from = NULL, *subject = NULL;
109    char *CAfile = NULL, *CApath = NULL;
110    char *passargin = NULL, *passin = NULL;
111    char *inrand = NULL;
112    int need_rand = 0;
113    int indef = 0;
114    const EVP_MD *sign_md = NULL;
115    int informat = FORMAT_SMIME, outformat = FORMAT_SMIME;
116    int keyform = FORMAT_PEM;
117#ifndef OPENSSL_NO_ENGINE
118    char *engine = NULL;
119#endif
120
121    X509_VERIFY_PARAM *vpm = NULL;
122
123    args = argv + 1;
124    ret = 1;
125
126    apps_startup();
127
128    if (bio_err == NULL) {
129        if ((bio_err = BIO_new(BIO_s_file())) != NULL)
130            BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
131    }
132
133    if (!load_config(bio_err, NULL))
134        goto end;
135
136    while (!badarg && *args && *args[0] == '-') {
137        if (!strcmp(*args, "-encrypt"))
138            operation = SMIME_ENCRYPT;
139        else if (!strcmp(*args, "-decrypt"))
140            operation = SMIME_DECRYPT;
141        else if (!strcmp(*args, "-sign"))
142            operation = SMIME_SIGN;
143        else if (!strcmp(*args, "-resign"))
144            operation = SMIME_RESIGN;
145        else if (!strcmp(*args, "-verify"))
146            operation = SMIME_VERIFY;
147        else if (!strcmp(*args, "-pk7out"))
148            operation = SMIME_PK7OUT;
149#ifndef OPENSSL_NO_DES
150        else if (!strcmp(*args, "-des3"))
151            cipher = EVP_des_ede3_cbc();
152        else if (!strcmp(*args, "-des"))
153            cipher = EVP_des_cbc();
154#endif
155#ifndef OPENSSL_NO_SEED
156        else if (!strcmp(*args, "-seed"))
157            cipher = EVP_seed_cbc();
158#endif
159#ifndef OPENSSL_NO_RC2
160        else if (!strcmp(*args, "-rc2-40"))
161            cipher = EVP_rc2_40_cbc();
162        else if (!strcmp(*args, "-rc2-128"))
163            cipher = EVP_rc2_cbc();
164        else if (!strcmp(*args, "-rc2-64"))
165            cipher = EVP_rc2_64_cbc();
166#endif
167#ifndef OPENSSL_NO_AES
168        else if (!strcmp(*args, "-aes128"))
169            cipher = EVP_aes_128_cbc();
170        else if (!strcmp(*args, "-aes192"))
171            cipher = EVP_aes_192_cbc();
172        else if (!strcmp(*args, "-aes256"))
173            cipher = EVP_aes_256_cbc();
174#endif
175#ifndef OPENSSL_NO_CAMELLIA
176        else if (!strcmp(*args, "-camellia128"))
177            cipher = EVP_camellia_128_cbc();
178        else if (!strcmp(*args, "-camellia192"))
179            cipher = EVP_camellia_192_cbc();
180        else if (!strcmp(*args, "-camellia256"))
181            cipher = EVP_camellia_256_cbc();
182#endif
183        else if (!strcmp(*args, "-text"))
184            flags |= PKCS7_TEXT;
185        else if (!strcmp(*args, "-nointern"))
186            flags |= PKCS7_NOINTERN;
187        else if (!strcmp(*args, "-noverify"))
188            flags |= PKCS7_NOVERIFY;
189        else if (!strcmp(*args, "-nochain"))
190            flags |= PKCS7_NOCHAIN;
191        else if (!strcmp(*args, "-nocerts"))
192            flags |= PKCS7_NOCERTS;
193        else if (!strcmp(*args, "-noattr"))
194            flags |= PKCS7_NOATTR;
195        else if (!strcmp(*args, "-nodetach"))
196            flags &= ~PKCS7_DETACHED;
197        else if (!strcmp(*args, "-nosmimecap"))
198            flags |= PKCS7_NOSMIMECAP;
199        else if (!strcmp(*args, "-binary"))
200            flags |= PKCS7_BINARY;
201        else if (!strcmp(*args, "-nosigs"))
202            flags |= PKCS7_NOSIGS;
203        else if (!strcmp(*args, "-stream"))
204            indef = 1;
205        else if (!strcmp(*args, "-indef"))
206            indef = 1;
207        else if (!strcmp(*args, "-noindef"))
208            indef = 0;
209        else if (!strcmp(*args, "-nooldmime"))
210            flags |= PKCS7_NOOLDMIMETYPE;
211        else if (!strcmp(*args, "-crlfeol"))
212            flags |= PKCS7_CRLFEOL;
213        else if (!strcmp(*args, "-rand")) {
214            if (!args[1])
215                goto argerr;
216            args++;
217            inrand = *args;
218            need_rand = 1;
219        }
220#ifndef OPENSSL_NO_ENGINE
221        else if (!strcmp(*args, "-engine")) {
222            if (!args[1])
223                goto argerr;
224            engine = *++args;
225        }
226#endif
227        else if (!strcmp(*args, "-passin")) {
228            if (!args[1])
229                goto argerr;
230            passargin = *++args;
231        } else if (!strcmp(*args, "-to")) {
232            if (!args[1])
233                goto argerr;
234            to = *++args;
235        } else if (!strcmp(*args, "-from")) {
236            if (!args[1])
237                goto argerr;
238            from = *++args;
239        } else if (!strcmp(*args, "-subject")) {
240            if (!args[1])
241                goto argerr;
242            subject = *++args;
243        } else if (!strcmp(*args, "-signer")) {
244            if (!args[1])
245                goto argerr;
246            /* If previous -signer argument add signer to list */
247
248            if (signerfile) {
249                if (!sksigners)
250                    sksigners = sk_OPENSSL_STRING_new_null();
251                sk_OPENSSL_STRING_push(sksigners, signerfile);
252                if (!keyfile)
253                    keyfile = signerfile;
254                if (!skkeys)
255                    skkeys = sk_OPENSSL_STRING_new_null();
256                sk_OPENSSL_STRING_push(skkeys, keyfile);
257                keyfile = NULL;
258            }
259            signerfile = *++args;
260        } else if (!strcmp(*args, "-recip")) {
261            if (!args[1])
262                goto argerr;
263            recipfile = *++args;
264        } else if (!strcmp(*args, "-md")) {
265            if (!args[1])
266                goto argerr;
267            sign_md = EVP_get_digestbyname(*++args);
268            if (sign_md == NULL) {
269                BIO_printf(bio_err, "Unknown digest %s\n", *args);
270                goto argerr;
271            }
272        } else if (!strcmp(*args, "-inkey")) {
273            if (!args[1])
274                goto argerr;
275            /* If previous -inkey arument add signer to list */
276            if (keyfile) {
277                if (!signerfile) {
278                    BIO_puts(bio_err, "Illegal -inkey without -signer\n");
279                    goto argerr;
280                }
281                if (!sksigners)
282                    sksigners = sk_OPENSSL_STRING_new_null();
283                sk_OPENSSL_STRING_push(sksigners, signerfile);
284                signerfile = NULL;
285                if (!skkeys)
286                    skkeys = sk_OPENSSL_STRING_new_null();
287                sk_OPENSSL_STRING_push(skkeys, keyfile);
288            }
289            keyfile = *++args;
290        } else if (!strcmp(*args, "-keyform")) {
291            if (!args[1])
292                goto argerr;
293            keyform = str2fmt(*++args);
294        } else if (!strcmp(*args, "-certfile")) {
295            if (!args[1])
296                goto argerr;
297            certfile = *++args;
298        } else if (!strcmp(*args, "-CAfile")) {
299            if (!args[1])
300                goto argerr;
301            CAfile = *++args;
302        } else if (!strcmp(*args, "-CApath")) {
303            if (!args[1])
304                goto argerr;
305            CApath = *++args;
306        } else if (!strcmp(*args, "-in")) {
307            if (!args[1])
308                goto argerr;
309            infile = *++args;
310        } else if (!strcmp(*args, "-inform")) {
311            if (!args[1])
312                goto argerr;
313            informat = str2fmt(*++args);
314        } else if (!strcmp(*args, "-outform")) {
315            if (!args[1])
316                goto argerr;
317            outformat = str2fmt(*++args);
318        } else if (!strcmp(*args, "-out")) {
319            if (!args[1])
320                goto argerr;
321            outfile = *++args;
322        } else if (!strcmp(*args, "-content")) {
323            if (!args[1])
324                goto argerr;
325            contfile = *++args;
326        } else if (args_verify(&args, NULL, &badarg, bio_err, &vpm))
327            continue;
328        else if ((cipher = EVP_get_cipherbyname(*args + 1)) == NULL)
329            badarg = 1;
330        args++;
331    }
332
333    if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) {
334        BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
335        goto argerr;
336    }
337
338    if (operation & SMIME_SIGNERS) {
339        /* Check to see if any final signer needs to be appended */
340        if (keyfile && !signerfile) {
341            BIO_puts(bio_err, "Illegal -inkey without -signer\n");
342            goto argerr;
343        }
344        if (signerfile) {
345            if (!sksigners)
346                sksigners = sk_OPENSSL_STRING_new_null();
347            sk_OPENSSL_STRING_push(sksigners, signerfile);
348            if (!skkeys)
349                skkeys = sk_OPENSSL_STRING_new_null();
350            if (!keyfile)
351                keyfile = signerfile;
352            sk_OPENSSL_STRING_push(skkeys, keyfile);
353        }
354        if (!sksigners) {
355            BIO_printf(bio_err, "No signer certificate specified\n");
356            badarg = 1;
357        }
358        signerfile = NULL;
359        keyfile = NULL;
360        need_rand = 1;
361    } else if (operation == SMIME_DECRYPT) {
362        if (!recipfile && !keyfile) {
363            BIO_printf(bio_err,
364                       "No recipient certificate or key specified\n");
365            badarg = 1;
366        }
367    } else if (operation == SMIME_ENCRYPT) {
368        if (!*args) {
369            BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
370            badarg = 1;
371        }
372        need_rand = 1;
373    } else if (!operation)
374        badarg = 1;
375
376    if (badarg) {
377 argerr:
378        BIO_printf(bio_err, "Usage smime [options] cert.pem ...\n");
379        BIO_printf(bio_err, "where options are\n");
380        BIO_printf(bio_err, "-encrypt       encrypt message\n");
381        BIO_printf(bio_err, "-decrypt       decrypt encrypted message\n");
382        BIO_printf(bio_err, "-sign          sign message\n");
383        BIO_printf(bio_err, "-verify        verify signed message\n");
384        BIO_printf(bio_err, "-pk7out        output PKCS#7 structure\n");
385#ifndef OPENSSL_NO_DES
386        BIO_printf(bio_err, "-des3          encrypt with triple DES\n");
387        BIO_printf(bio_err, "-des           encrypt with DES\n");
388#endif
389#ifndef OPENSSL_NO_SEED
390        BIO_printf(bio_err, "-seed          encrypt with SEED\n");
391#endif
392#ifndef OPENSSL_NO_RC2
393        BIO_printf(bio_err, "-rc2-40        encrypt with RC2-40 (default)\n");
394        BIO_printf(bio_err, "-rc2-64        encrypt with RC2-64\n");
395        BIO_printf(bio_err, "-rc2-128       encrypt with RC2-128\n");
396#endif
397#ifndef OPENSSL_NO_AES
398        BIO_printf(bio_err, "-aes128, -aes192, -aes256\n");
399        BIO_printf(bio_err,
400                   "               encrypt PEM output with cbc aes\n");
401#endif
402#ifndef OPENSSL_NO_CAMELLIA
403        BIO_printf(bio_err, "-camellia128, -camellia192, -camellia256\n");
404        BIO_printf(bio_err,
405                   "               encrypt PEM output with cbc camellia\n");
406#endif
407        BIO_printf(bio_err,
408                   "-nointern      don't search certificates in message for signer\n");
409        BIO_printf(bio_err,
410                   "-nosigs        don't verify message signature\n");
411        BIO_printf(bio_err,
412                   "-noverify      don't verify signers certificate\n");
413        BIO_printf(bio_err,
414                   "-nocerts       don't include signers certificate when signing\n");
415        BIO_printf(bio_err, "-nodetach      use opaque signing\n");
416        BIO_printf(bio_err,
417                   "-noattr        don't include any signed attributes\n");
418        BIO_printf(bio_err,
419                   "-binary        don't translate message to text\n");
420        BIO_printf(bio_err, "-certfile file other certificates file\n");
421        BIO_printf(bio_err, "-signer file   signer certificate file\n");
422        BIO_printf(bio_err,
423                   "-recip  file   recipient certificate file for decryption\n");
424        BIO_printf(bio_err, "-in file       input file\n");
425        BIO_printf(bio_err,
426                   "-inform arg    input format SMIME (default), PEM or DER\n");
427        BIO_printf(bio_err,
428                   "-inkey file    input private key (if not signer or recipient)\n");
429        BIO_printf(bio_err,
430                   "-keyform arg   input private key format (PEM or ENGINE)\n");
431        BIO_printf(bio_err, "-out file      output file\n");
432        BIO_printf(bio_err,
433                   "-outform arg   output format SMIME (default), PEM or DER\n");
434        BIO_printf(bio_err,
435                   "-content file  supply or override content for detached signature\n");
436        BIO_printf(bio_err, "-to addr       to address\n");
437        BIO_printf(bio_err, "-from ad       from address\n");
438        BIO_printf(bio_err, "-subject s     subject\n");
439        BIO_printf(bio_err,
440                   "-text          include or delete text MIME headers\n");
441        BIO_printf(bio_err,
442                   "-CApath dir    trusted certificates directory\n");
443        BIO_printf(bio_err, "-CAfile file   trusted certificates file\n");
444        BIO_printf(bio_err,
445                   "-no_alt_chains only ever use the first certificate chain found\n");
446        BIO_printf(bio_err,
447                   "-crl_check     check revocation status of signer's certificate using CRLs\n");
448        BIO_printf(bio_err,
449                   "-crl_check_all check revocation status of signer's certificate chain using CRLs\n");
450#ifndef OPENSSL_NO_ENGINE
451        BIO_printf(bio_err,
452                   "-engine e      use engine e, possibly a hardware device.\n");
453#endif
454        BIO_printf(bio_err, "-passin arg    input file pass phrase source\n");
455        BIO_printf(bio_err, "-rand file%cfile%c...\n", LIST_SEPARATOR_CHAR,
456                   LIST_SEPARATOR_CHAR);
457        BIO_printf(bio_err,
458                   "               load the file (or the files in the directory) into\n");
459        BIO_printf(bio_err, "               the random number generator\n");
460        BIO_printf(bio_err,
461                   "cert.pem       recipient certificate(s) for encryption\n");
462        goto end;
463    }
464#ifndef OPENSSL_NO_ENGINE
465    e = setup_engine(bio_err, engine, 0);
466#endif
467
468    if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
469        BIO_printf(bio_err, "Error getting password\n");
470        goto end;
471    }
472
473    if (need_rand) {
474        app_RAND_load_file(NULL, bio_err, (inrand != NULL));
475        if (inrand != NULL)
476            BIO_printf(bio_err, "%ld semi-random bytes loaded\n",
477                       app_RAND_load_files(inrand));
478    }
479
480    ret = 2;
481
482    if (!(operation & SMIME_SIGNERS))
483        flags &= ~PKCS7_DETACHED;
484
485    if (operation & SMIME_OP) {
486        if (outformat == FORMAT_ASN1)
487            outmode = "wb";
488    } else {
489        if (flags & PKCS7_BINARY)
490            outmode = "wb";
491    }
492
493    if (operation & SMIME_IP) {
494        if (informat == FORMAT_ASN1)
495            inmode = "rb";
496    } else {
497        if (flags & PKCS7_BINARY)
498            inmode = "rb";
499    }
500
501    if (operation == SMIME_ENCRYPT) {
502        if (!cipher) {
503#ifndef OPENSSL_NO_DES
504            cipher = EVP_des_ede3_cbc();
505#else
506            BIO_printf(bio_err, "No cipher selected\n");
507            goto end;
508#endif
509        }
510        encerts = sk_X509_new_null();
511        while (*args) {
512            if (!(cert = load_cert(bio_err, *args, FORMAT_PEM,
513                                   NULL, e, "recipient certificate file"))) {
514#if 0                           /* An appropriate message is already printed */
515                BIO_printf(bio_err,
516                           "Can't read recipient certificate file %s\n",
517                           *args);
518#endif
519                goto end;
520            }
521            sk_X509_push(encerts, cert);
522            cert = NULL;
523            args++;
524        }
525    }
526
527    if (certfile) {
528        if (!(other = load_certs(bio_err, certfile, FORMAT_PEM, NULL,
529                                 e, "certificate file"))) {
530            ERR_print_errors(bio_err);
531            goto end;
532        }
533    }
534
535    if (recipfile && (operation == SMIME_DECRYPT)) {
536        if (!(recip = load_cert(bio_err, recipfile, FORMAT_PEM, NULL,
537                                e, "recipient certificate file"))) {
538            ERR_print_errors(bio_err);
539            goto end;
540        }
541    }
542
543    if (operation == SMIME_DECRYPT) {
544        if (!keyfile)
545            keyfile = recipfile;
546    } else if (operation == SMIME_SIGN) {
547        if (!keyfile)
548            keyfile = signerfile;
549    } else
550        keyfile = NULL;
551
552    if (keyfile) {
553        key = load_key(bio_err, keyfile, keyform, 0, passin, e,
554                       "signing key file");
555        if (!key)
556            goto end;
557    }
558
559    if (infile) {
560        if (!(in = BIO_new_file(infile, inmode))) {
561            BIO_printf(bio_err, "Can't open input file %s\n", infile);
562            goto end;
563        }
564    } else
565        in = BIO_new_fp(stdin, BIO_NOCLOSE);
566
567    if (operation & SMIME_IP) {
568        if (informat == FORMAT_SMIME)
569            p7 = SMIME_read_PKCS7(in, &indata);
570        else if (informat == FORMAT_PEM)
571            p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
572        else if (informat == FORMAT_ASN1)
573            p7 = d2i_PKCS7_bio(in, NULL);
574        else {
575            BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
576            goto end;
577        }
578
579        if (!p7) {
580            BIO_printf(bio_err, "Error reading S/MIME message\n");
581            goto end;
582        }
583        if (contfile) {
584            BIO_free(indata);
585            if (!(indata = BIO_new_file(contfile, "rb"))) {
586                BIO_printf(bio_err, "Can't read content file %s\n", contfile);
587                goto end;
588            }
589        }
590    }
591
592    if (outfile) {
593        if (!(out = BIO_new_file(outfile, outmode))) {
594            BIO_printf(bio_err, "Can't open output file %s\n", outfile);
595            goto end;
596        }
597    } else {
598        out = BIO_new_fp(stdout, BIO_NOCLOSE);
599#ifdef OPENSSL_SYS_VMS
600        {
601            BIO *tmpbio = BIO_new(BIO_f_linebuffer());
602            out = BIO_push(tmpbio, out);
603        }
604#endif
605    }
606
607    if (operation == SMIME_VERIFY) {
608        if (!(store = setup_verify(bio_err, CAfile, CApath)))
609            goto end;
610        X509_STORE_set_verify_cb(store, smime_cb);
611        if (vpm)
612            X509_STORE_set1_param(store, vpm);
613    }
614
615    ret = 3;
616
617    if (operation == SMIME_ENCRYPT) {
618        if (indef)
619            flags |= PKCS7_STREAM;
620        p7 = PKCS7_encrypt(encerts, in, cipher, flags);
621    } else if (operation & SMIME_SIGNERS) {
622        int i;
623        /*
624         * If detached data content we only enable streaming if S/MIME output
625         * format.
626         */
627        if (operation == SMIME_SIGN) {
628            if (flags & PKCS7_DETACHED) {
629                if (outformat == FORMAT_SMIME)
630                    flags |= PKCS7_STREAM;
631            } else if (indef)
632                flags |= PKCS7_STREAM;
633            flags |= PKCS7_PARTIAL;
634            p7 = PKCS7_sign(NULL, NULL, other, in, flags);
635            if (!p7)
636                goto end;
637        } else
638            flags |= PKCS7_REUSE_DIGEST;
639        for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) {
640            signerfile = sk_OPENSSL_STRING_value(sksigners, i);
641            keyfile = sk_OPENSSL_STRING_value(skkeys, i);
642            signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL,
643                               e, "signer certificate");
644            if (!signer)
645                goto end;
646            key = load_key(bio_err, keyfile, keyform, 0, passin, e,
647                           "signing key file");
648            if (!key)
649                goto end;
650            if (!PKCS7_sign_add_signer(p7, signer, key, sign_md, flags))
651                goto end;
652            X509_free(signer);
653            signer = NULL;
654            EVP_PKEY_free(key);
655            key = NULL;
656        }
657        /* If not streaming or resigning finalize structure */
658        if ((operation == SMIME_SIGN) && !(flags & PKCS7_STREAM)) {
659            if (!PKCS7_final(p7, in, flags))
660                goto end;
661        }
662    }
663
664    if (!p7) {
665        BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
666        goto end;
667    }
668
669    ret = 4;
670    if (operation == SMIME_DECRYPT) {
671        if (!PKCS7_decrypt(p7, key, recip, out, flags)) {
672            BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n");
673            goto end;
674        }
675    } else if (operation == SMIME_VERIFY) {
676        STACK_OF(X509) *signers;
677        if (PKCS7_verify(p7, other, store, indata, out, flags))
678            BIO_printf(bio_err, "Verification successful\n");
679        else {
680            BIO_printf(bio_err, "Verification failure\n");
681            goto end;
682        }
683        signers = PKCS7_get0_signers(p7, other, flags);
684        if (!save_certs(signerfile, signers)) {
685            BIO_printf(bio_err, "Error writing signers to %s\n", signerfile);
686            ret = 5;
687            goto end;
688        }
689        sk_X509_free(signers);
690    } else if (operation == SMIME_PK7OUT)
691        PEM_write_bio_PKCS7(out, p7);
692    else {
693        if (to)
694            BIO_printf(out, "To: %s\n", to);
695        if (from)
696            BIO_printf(out, "From: %s\n", from);
697        if (subject)
698            BIO_printf(out, "Subject: %s\n", subject);
699        if (outformat == FORMAT_SMIME) {
700            if (operation == SMIME_RESIGN)
701                SMIME_write_PKCS7(out, p7, indata, flags);
702            else
703                SMIME_write_PKCS7(out, p7, in, flags);
704        } else if (outformat == FORMAT_PEM)
705            PEM_write_bio_PKCS7_stream(out, p7, in, flags);
706        else if (outformat == FORMAT_ASN1)
707            i2d_PKCS7_bio_stream(out, p7, in, flags);
708        else {
709            BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
710            goto end;
711        }
712    }
713    ret = 0;
714 end:
715    if (need_rand)
716        app_RAND_write_file(NULL, bio_err);
717    if (ret)
718        ERR_print_errors(bio_err);
719    sk_X509_pop_free(encerts, X509_free);
720    sk_X509_pop_free(other, X509_free);
721    if (vpm)
722        X509_VERIFY_PARAM_free(vpm);
723    if (sksigners)
724        sk_OPENSSL_STRING_free(sksigners);
725    if (skkeys)
726        sk_OPENSSL_STRING_free(skkeys);
727    X509_STORE_free(store);
728    X509_free(cert);
729    X509_free(recip);
730    X509_free(signer);
731    EVP_PKEY_free(key);
732    PKCS7_free(p7);
733    BIO_free(in);
734    BIO_free(indata);
735    BIO_free_all(out);
736    if (passin)
737        OPENSSL_free(passin);
738    return (ret);
739}
740
741static int save_certs(char *signerfile, STACK_OF(X509) *signers)
742{
743    int i;
744    BIO *tmp;
745    if (!signerfile)
746        return 1;
747    tmp = BIO_new_file(signerfile, "w");
748    if (!tmp)
749        return 0;
750    for (i = 0; i < sk_X509_num(signers); i++)
751        PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
752    BIO_free(tmp);
753    return 1;
754}
755
756/* Minimal callback just to output policy info (if any) */
757
758static int smime_cb(int ok, X509_STORE_CTX *ctx)
759{
760    int error;
761
762    error = X509_STORE_CTX_get_error(ctx);
763
764    if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
765        && ((error != X509_V_OK) || (ok != 2)))
766        return ok;
767
768    policies_print(NULL, ctx);
769
770    return ok;
771
772}
773