smime.c revision 280304
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                   "-crl_check     check revocation status of signer's certificate using CRLs\n");
446        BIO_printf(bio_err,
447                   "-crl_check_all check revocation status of signer's certificate chain using CRLs\n");
448#ifndef OPENSSL_NO_ENGINE
449        BIO_printf(bio_err,
450                   "-engine e      use engine e, possibly a hardware device.\n");
451#endif
452        BIO_printf(bio_err, "-passin arg    input file pass phrase source\n");
453        BIO_printf(bio_err, "-rand file%cfile%c...\n", LIST_SEPARATOR_CHAR,
454                   LIST_SEPARATOR_CHAR);
455        BIO_printf(bio_err,
456                   "               load the file (or the files in the directory) into\n");
457        BIO_printf(bio_err, "               the random number generator\n");
458        BIO_printf(bio_err,
459                   "cert.pem       recipient certificate(s) for encryption\n");
460        goto end;
461    }
462#ifndef OPENSSL_NO_ENGINE
463    e = setup_engine(bio_err, engine, 0);
464#endif
465
466    if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
467        BIO_printf(bio_err, "Error getting password\n");
468        goto end;
469    }
470
471    if (need_rand) {
472        app_RAND_load_file(NULL, bio_err, (inrand != NULL));
473        if (inrand != NULL)
474            BIO_printf(bio_err, "%ld semi-random bytes loaded\n",
475                       app_RAND_load_files(inrand));
476    }
477
478    ret = 2;
479
480    if (!(operation & SMIME_SIGNERS))
481        flags &= ~PKCS7_DETACHED;
482
483    if (operation & SMIME_OP) {
484        if (outformat == FORMAT_ASN1)
485            outmode = "wb";
486    } else {
487        if (flags & PKCS7_BINARY)
488            outmode = "wb";
489    }
490
491    if (operation & SMIME_IP) {
492        if (informat == FORMAT_ASN1)
493            inmode = "rb";
494    } else {
495        if (flags & PKCS7_BINARY)
496            inmode = "rb";
497    }
498
499    if (operation == SMIME_ENCRYPT) {
500        if (!cipher) {
501#ifndef OPENSSL_NO_DES
502            cipher = EVP_des_ede3_cbc();
503#else
504            BIO_printf(bio_err, "No cipher selected\n");
505            goto end;
506#endif
507        }
508        encerts = sk_X509_new_null();
509        while (*args) {
510            if (!(cert = load_cert(bio_err, *args, FORMAT_PEM,
511                                   NULL, e, "recipient certificate file"))) {
512#if 0                           /* An appropriate message is already printed */
513                BIO_printf(bio_err,
514                           "Can't read recipient certificate file %s\n",
515                           *args);
516#endif
517                goto end;
518            }
519            sk_X509_push(encerts, cert);
520            cert = NULL;
521            args++;
522        }
523    }
524
525    if (certfile) {
526        if (!(other = load_certs(bio_err, certfile, FORMAT_PEM, NULL,
527                                 e, "certificate file"))) {
528            ERR_print_errors(bio_err);
529            goto end;
530        }
531    }
532
533    if (recipfile && (operation == SMIME_DECRYPT)) {
534        if (!(recip = load_cert(bio_err, recipfile, FORMAT_PEM, NULL,
535                                e, "recipient certificate file"))) {
536            ERR_print_errors(bio_err);
537            goto end;
538        }
539    }
540
541    if (operation == SMIME_DECRYPT) {
542        if (!keyfile)
543            keyfile = recipfile;
544    } else if (operation == SMIME_SIGN) {
545        if (!keyfile)
546            keyfile = signerfile;
547    } else
548        keyfile = NULL;
549
550    if (keyfile) {
551        key = load_key(bio_err, keyfile, keyform, 0, passin, e,
552                       "signing key file");
553        if (!key)
554            goto end;
555    }
556
557    if (infile) {
558        if (!(in = BIO_new_file(infile, inmode))) {
559            BIO_printf(bio_err, "Can't open input file %s\n", infile);
560            goto end;
561        }
562    } else
563        in = BIO_new_fp(stdin, BIO_NOCLOSE);
564
565    if (operation & SMIME_IP) {
566        if (informat == FORMAT_SMIME)
567            p7 = SMIME_read_PKCS7(in, &indata);
568        else if (informat == FORMAT_PEM)
569            p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
570        else if (informat == FORMAT_ASN1)
571            p7 = d2i_PKCS7_bio(in, NULL);
572        else {
573            BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
574            goto end;
575        }
576
577        if (!p7) {
578            BIO_printf(bio_err, "Error reading S/MIME message\n");
579            goto end;
580        }
581        if (contfile) {
582            BIO_free(indata);
583            if (!(indata = BIO_new_file(contfile, "rb"))) {
584                BIO_printf(bio_err, "Can't read content file %s\n", contfile);
585                goto end;
586            }
587        }
588    }
589
590    if (outfile) {
591        if (!(out = BIO_new_file(outfile, outmode))) {
592            BIO_printf(bio_err, "Can't open output file %s\n", outfile);
593            goto end;
594        }
595    } else {
596        out = BIO_new_fp(stdout, BIO_NOCLOSE);
597#ifdef OPENSSL_SYS_VMS
598        {
599            BIO *tmpbio = BIO_new(BIO_f_linebuffer());
600            out = BIO_push(tmpbio, out);
601        }
602#endif
603    }
604
605    if (operation == SMIME_VERIFY) {
606        if (!(store = setup_verify(bio_err, CAfile, CApath)))
607            goto end;
608        X509_STORE_set_verify_cb(store, smime_cb);
609        if (vpm)
610            X509_STORE_set1_param(store, vpm);
611    }
612
613    ret = 3;
614
615    if (operation == SMIME_ENCRYPT) {
616        if (indef)
617            flags |= PKCS7_STREAM;
618        p7 = PKCS7_encrypt(encerts, in, cipher, flags);
619    } else if (operation & SMIME_SIGNERS) {
620        int i;
621        /*
622         * If detached data content we only enable streaming if S/MIME output
623         * format.
624         */
625        if (operation == SMIME_SIGN) {
626            if (flags & PKCS7_DETACHED) {
627                if (outformat == FORMAT_SMIME)
628                    flags |= PKCS7_STREAM;
629            } else if (indef)
630                flags |= PKCS7_STREAM;
631            flags |= PKCS7_PARTIAL;
632            p7 = PKCS7_sign(NULL, NULL, other, in, flags);
633            if (!p7)
634                goto end;
635        } else
636            flags |= PKCS7_REUSE_DIGEST;
637        for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) {
638            signerfile = sk_OPENSSL_STRING_value(sksigners, i);
639            keyfile = sk_OPENSSL_STRING_value(skkeys, i);
640            signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL,
641                               e, "signer certificate");
642            if (!signer)
643                goto end;
644            key = load_key(bio_err, keyfile, keyform, 0, passin, e,
645                           "signing key file");
646            if (!key)
647                goto end;
648            if (!PKCS7_sign_add_signer(p7, signer, key, sign_md, flags))
649                goto end;
650            X509_free(signer);
651            signer = NULL;
652            EVP_PKEY_free(key);
653            key = NULL;
654        }
655        /* If not streaming or resigning finalize structure */
656        if ((operation == SMIME_SIGN) && !(flags & PKCS7_STREAM)) {
657            if (!PKCS7_final(p7, in, flags))
658                goto end;
659        }
660    }
661
662    if (!p7) {
663        BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
664        goto end;
665    }
666
667    ret = 4;
668    if (operation == SMIME_DECRYPT) {
669        if (!PKCS7_decrypt(p7, key, recip, out, flags)) {
670            BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n");
671            goto end;
672        }
673    } else if (operation == SMIME_VERIFY) {
674        STACK_OF(X509) *signers;
675        if (PKCS7_verify(p7, other, store, indata, out, flags))
676            BIO_printf(bio_err, "Verification successful\n");
677        else {
678            BIO_printf(bio_err, "Verification failure\n");
679            goto end;
680        }
681        signers = PKCS7_get0_signers(p7, other, flags);
682        if (!save_certs(signerfile, signers)) {
683            BIO_printf(bio_err, "Error writing signers to %s\n", signerfile);
684            ret = 5;
685            goto end;
686        }
687        sk_X509_free(signers);
688    } else if (operation == SMIME_PK7OUT)
689        PEM_write_bio_PKCS7(out, p7);
690    else {
691        if (to)
692            BIO_printf(out, "To: %s\n", to);
693        if (from)
694            BIO_printf(out, "From: %s\n", from);
695        if (subject)
696            BIO_printf(out, "Subject: %s\n", subject);
697        if (outformat == FORMAT_SMIME) {
698            if (operation == SMIME_RESIGN)
699                SMIME_write_PKCS7(out, p7, indata, flags);
700            else
701                SMIME_write_PKCS7(out, p7, in, flags);
702        } else if (outformat == FORMAT_PEM)
703            PEM_write_bio_PKCS7_stream(out, p7, in, flags);
704        else if (outformat == FORMAT_ASN1)
705            i2d_PKCS7_bio_stream(out, p7, in, flags);
706        else {
707            BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
708            goto end;
709        }
710    }
711    ret = 0;
712 end:
713    if (need_rand)
714        app_RAND_write_file(NULL, bio_err);
715    if (ret)
716        ERR_print_errors(bio_err);
717    sk_X509_pop_free(encerts, X509_free);
718    sk_X509_pop_free(other, X509_free);
719    if (vpm)
720        X509_VERIFY_PARAM_free(vpm);
721    if (sksigners)
722        sk_OPENSSL_STRING_free(sksigners);
723    if (skkeys)
724        sk_OPENSSL_STRING_free(skkeys);
725    X509_STORE_free(store);
726    X509_free(cert);
727    X509_free(recip);
728    X509_free(signer);
729    EVP_PKEY_free(key);
730    PKCS7_free(p7);
731    BIO_free(in);
732    BIO_free(indata);
733    BIO_free_all(out);
734    if (passin)
735        OPENSSL_free(passin);
736    return (ret);
737}
738
739static int save_certs(char *signerfile, STACK_OF(X509) *signers)
740{
741    int i;
742    BIO *tmp;
743    if (!signerfile)
744        return 1;
745    tmp = BIO_new_file(signerfile, "w");
746    if (!tmp)
747        return 0;
748    for (i = 0; i < sk_X509_num(signers); i++)
749        PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
750    BIO_free(tmp);
751    return 1;
752}
753
754/* Minimal callback just to output policy info (if any) */
755
756static int smime_cb(int ok, X509_STORE_CTX *ctx)
757{
758    int error;
759
760    error = X509_STORE_CTX_get_error(ctx);
761
762    if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
763        && ((error != X509_V_OK) || (ok != 2)))
764        return ok;
765
766    policies_print(NULL, ctx);
767
768    return ok;
769
770}
771