smime.c revision 312826
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    char *engine = NULL;
118
119    X509_VERIFY_PARAM *vpm = NULL;
120
121    args = argv + 1;
122    ret = 1;
123
124    apps_startup();
125
126    if (bio_err == NULL) {
127        if ((bio_err = BIO_new(BIO_s_file())) != NULL)
128            BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
129    }
130
131    if (!load_config(bio_err, NULL))
132        goto end;
133
134    while (!badarg && *args && *args[0] == '-') {
135        if (!strcmp(*args, "-encrypt"))
136            operation = SMIME_ENCRYPT;
137        else if (!strcmp(*args, "-decrypt"))
138            operation = SMIME_DECRYPT;
139        else if (!strcmp(*args, "-sign"))
140            operation = SMIME_SIGN;
141        else if (!strcmp(*args, "-resign"))
142            operation = SMIME_RESIGN;
143        else if (!strcmp(*args, "-verify"))
144            operation = SMIME_VERIFY;
145        else if (!strcmp(*args, "-pk7out"))
146            operation = SMIME_PK7OUT;
147#ifndef OPENSSL_NO_DES
148        else if (!strcmp(*args, "-des3"))
149            cipher = EVP_des_ede3_cbc();
150        else if (!strcmp(*args, "-des"))
151            cipher = EVP_des_cbc();
152#endif
153#ifndef OPENSSL_NO_SEED
154        else if (!strcmp(*args, "-seed"))
155            cipher = EVP_seed_cbc();
156#endif
157#ifndef OPENSSL_NO_RC2
158        else if (!strcmp(*args, "-rc2-40"))
159            cipher = EVP_rc2_40_cbc();
160        else if (!strcmp(*args, "-rc2-128"))
161            cipher = EVP_rc2_cbc();
162        else if (!strcmp(*args, "-rc2-64"))
163            cipher = EVP_rc2_64_cbc();
164#endif
165#ifndef OPENSSL_NO_AES
166        else if (!strcmp(*args, "-aes128"))
167            cipher = EVP_aes_128_cbc();
168        else if (!strcmp(*args, "-aes192"))
169            cipher = EVP_aes_192_cbc();
170        else if (!strcmp(*args, "-aes256"))
171            cipher = EVP_aes_256_cbc();
172#endif
173#ifndef OPENSSL_NO_CAMELLIA
174        else if (!strcmp(*args, "-camellia128"))
175            cipher = EVP_camellia_128_cbc();
176        else if (!strcmp(*args, "-camellia192"))
177            cipher = EVP_camellia_192_cbc();
178        else if (!strcmp(*args, "-camellia256"))
179            cipher = EVP_camellia_256_cbc();
180#endif
181        else if (!strcmp(*args, "-text"))
182            flags |= PKCS7_TEXT;
183        else if (!strcmp(*args, "-nointern"))
184            flags |= PKCS7_NOINTERN;
185        else if (!strcmp(*args, "-noverify"))
186            flags |= PKCS7_NOVERIFY;
187        else if (!strcmp(*args, "-nochain"))
188            flags |= PKCS7_NOCHAIN;
189        else if (!strcmp(*args, "-nocerts"))
190            flags |= PKCS7_NOCERTS;
191        else if (!strcmp(*args, "-noattr"))
192            flags |= PKCS7_NOATTR;
193        else if (!strcmp(*args, "-nodetach"))
194            flags &= ~PKCS7_DETACHED;
195        else if (!strcmp(*args, "-nosmimecap"))
196            flags |= PKCS7_NOSMIMECAP;
197        else if (!strcmp(*args, "-binary"))
198            flags |= PKCS7_BINARY;
199        else if (!strcmp(*args, "-nosigs"))
200            flags |= PKCS7_NOSIGS;
201        else if (!strcmp(*args, "-stream"))
202            indef = 1;
203        else if (!strcmp(*args, "-indef"))
204            indef = 1;
205        else if (!strcmp(*args, "-noindef"))
206            indef = 0;
207        else if (!strcmp(*args, "-nooldmime"))
208            flags |= PKCS7_NOOLDMIMETYPE;
209        else if (!strcmp(*args, "-crlfeol"))
210            flags |= PKCS7_CRLFEOL;
211        else if (!strcmp(*args, "-rand")) {
212            if (!args[1])
213                goto argerr;
214            args++;
215            inrand = *args;
216            need_rand = 1;
217        }
218#ifndef OPENSSL_NO_ENGINE
219        else if (!strcmp(*args, "-engine")) {
220            if (!args[1])
221                goto argerr;
222            engine = *++args;
223        }
224#endif
225        else if (!strcmp(*args, "-passin")) {
226            if (!args[1])
227                goto argerr;
228            passargin = *++args;
229        } else if (!strcmp(*args, "-to")) {
230            if (!args[1])
231                goto argerr;
232            to = *++args;
233        } else if (!strcmp(*args, "-from")) {
234            if (!args[1])
235                goto argerr;
236            from = *++args;
237        } else if (!strcmp(*args, "-subject")) {
238            if (!args[1])
239                goto argerr;
240            subject = *++args;
241        } else if (!strcmp(*args, "-signer")) {
242            if (!args[1])
243                goto argerr;
244            /* If previous -signer argument add signer to list */
245
246            if (signerfile) {
247                if (!sksigners)
248                    sksigners = sk_OPENSSL_STRING_new_null();
249                sk_OPENSSL_STRING_push(sksigners, signerfile);
250                if (!keyfile)
251                    keyfile = signerfile;
252                if (!skkeys)
253                    skkeys = sk_OPENSSL_STRING_new_null();
254                sk_OPENSSL_STRING_push(skkeys, keyfile);
255                keyfile = NULL;
256            }
257            signerfile = *++args;
258        } else if (!strcmp(*args, "-recip")) {
259            if (!args[1])
260                goto argerr;
261            recipfile = *++args;
262        } else if (!strcmp(*args, "-md")) {
263            if (!args[1])
264                goto argerr;
265            sign_md = EVP_get_digestbyname(*++args);
266            if (sign_md == NULL) {
267                BIO_printf(bio_err, "Unknown digest %s\n", *args);
268                goto argerr;
269            }
270        } else if (!strcmp(*args, "-inkey")) {
271            if (!args[1])
272                goto argerr;
273            /* If previous -inkey arument add signer to list */
274            if (keyfile) {
275                if (!signerfile) {
276                    BIO_puts(bio_err, "Illegal -inkey without -signer\n");
277                    goto argerr;
278                }
279                if (!sksigners)
280                    sksigners = sk_OPENSSL_STRING_new_null();
281                sk_OPENSSL_STRING_push(sksigners, signerfile);
282                signerfile = NULL;
283                if (!skkeys)
284                    skkeys = sk_OPENSSL_STRING_new_null();
285                sk_OPENSSL_STRING_push(skkeys, keyfile);
286            }
287            keyfile = *++args;
288        } else if (!strcmp(*args, "-keyform")) {
289            if (!args[1])
290                goto argerr;
291            keyform = str2fmt(*++args);
292        } else if (!strcmp(*args, "-certfile")) {
293            if (!args[1])
294                goto argerr;
295            certfile = *++args;
296        } else if (!strcmp(*args, "-CAfile")) {
297            if (!args[1])
298                goto argerr;
299            CAfile = *++args;
300        } else if (!strcmp(*args, "-CApath")) {
301            if (!args[1])
302                goto argerr;
303            CApath = *++args;
304        } else if (!strcmp(*args, "-in")) {
305            if (!args[1])
306                goto argerr;
307            infile = *++args;
308        } else if (!strcmp(*args, "-inform")) {
309            if (!args[1])
310                goto argerr;
311            informat = str2fmt(*++args);
312        } else if (!strcmp(*args, "-outform")) {
313            if (!args[1])
314                goto argerr;
315            outformat = str2fmt(*++args);
316        } else if (!strcmp(*args, "-out")) {
317            if (!args[1])
318                goto argerr;
319            outfile = *++args;
320        } else if (!strcmp(*args, "-content")) {
321            if (!args[1])
322                goto argerr;
323            contfile = *++args;
324        } else if (args_verify(&args, NULL, &badarg, bio_err, &vpm))
325            continue;
326        else if ((cipher = EVP_get_cipherbyname(*args + 1)) == NULL)
327            badarg = 1;
328        args++;
329    }
330
331    if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) {
332        BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
333        goto argerr;
334    }
335
336    if (operation & SMIME_SIGNERS) {
337        /* Check to see if any final signer needs to be appended */
338        if (keyfile && !signerfile) {
339            BIO_puts(bio_err, "Illegal -inkey without -signer\n");
340            goto argerr;
341        }
342        if (signerfile) {
343            if (!sksigners)
344                sksigners = sk_OPENSSL_STRING_new_null();
345            sk_OPENSSL_STRING_push(sksigners, signerfile);
346            if (!skkeys)
347                skkeys = sk_OPENSSL_STRING_new_null();
348            if (!keyfile)
349                keyfile = signerfile;
350            sk_OPENSSL_STRING_push(skkeys, keyfile);
351        }
352        if (!sksigners) {
353            BIO_printf(bio_err, "No signer certificate specified\n");
354            badarg = 1;
355        }
356        signerfile = NULL;
357        keyfile = NULL;
358        need_rand = 1;
359    } else if (operation == SMIME_DECRYPT) {
360        if (!recipfile && !keyfile) {
361            BIO_printf(bio_err,
362                       "No recipient certificate or key specified\n");
363            badarg = 1;
364        }
365    } else if (operation == SMIME_ENCRYPT) {
366        if (!*args) {
367            BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
368            badarg = 1;
369        }
370        need_rand = 1;
371    } else if (!operation)
372        badarg = 1;
373
374    if (badarg) {
375 argerr:
376        BIO_printf(bio_err, "Usage smime [options] cert.pem ...\n");
377        BIO_printf(bio_err, "where options are\n");
378        BIO_printf(bio_err, "-encrypt       encrypt message\n");
379        BIO_printf(bio_err, "-decrypt       decrypt encrypted message\n");
380        BIO_printf(bio_err, "-sign          sign message\n");
381        BIO_printf(bio_err, "-verify        verify signed message\n");
382        BIO_printf(bio_err, "-pk7out        output PKCS#7 structure\n");
383#ifndef OPENSSL_NO_DES
384        BIO_printf(bio_err, "-des3          encrypt with triple DES\n");
385        BIO_printf(bio_err, "-des           encrypt with DES\n");
386#endif
387#ifndef OPENSSL_NO_SEED
388        BIO_printf(bio_err, "-seed          encrypt with SEED\n");
389#endif
390#ifndef OPENSSL_NO_RC2
391        BIO_printf(bio_err, "-rc2-40        encrypt with RC2-40 (default)\n");
392        BIO_printf(bio_err, "-rc2-64        encrypt with RC2-64\n");
393        BIO_printf(bio_err, "-rc2-128       encrypt with RC2-128\n");
394#endif
395#ifndef OPENSSL_NO_AES
396        BIO_printf(bio_err, "-aes128, -aes192, -aes256\n");
397        BIO_printf(bio_err,
398                   "               encrypt PEM output with cbc aes\n");
399#endif
400#ifndef OPENSSL_NO_CAMELLIA
401        BIO_printf(bio_err, "-camellia128, -camellia192, -camellia256\n");
402        BIO_printf(bio_err,
403                   "               encrypt PEM output with cbc camellia\n");
404#endif
405        BIO_printf(bio_err,
406                   "-nointern      don't search certificates in message for signer\n");
407        BIO_printf(bio_err,
408                   "-nosigs        don't verify message signature\n");
409        BIO_printf(bio_err,
410                   "-noverify      don't verify signers certificate\n");
411        BIO_printf(bio_err,
412                   "-nocerts       don't include signers certificate when signing\n");
413        BIO_printf(bio_err, "-nodetach      use opaque signing\n");
414        BIO_printf(bio_err,
415                   "-noattr        don't include any signed attributes\n");
416        BIO_printf(bio_err,
417                   "-binary        don't translate message to text\n");
418        BIO_printf(bio_err, "-certfile file other certificates file\n");
419        BIO_printf(bio_err, "-signer file   signer certificate file\n");
420        BIO_printf(bio_err,
421                   "-recip  file   recipient certificate file for decryption\n");
422        BIO_printf(bio_err, "-in file       input file\n");
423        BIO_printf(bio_err,
424                   "-inform arg    input format SMIME (default), PEM or DER\n");
425        BIO_printf(bio_err,
426                   "-inkey file    input private key (if not signer or recipient)\n");
427        BIO_printf(bio_err,
428                   "-keyform arg   input private key format (PEM or ENGINE)\n");
429        BIO_printf(bio_err, "-out file      output file\n");
430        BIO_printf(bio_err,
431                   "-outform arg   output format SMIME (default), PEM or DER\n");
432        BIO_printf(bio_err,
433                   "-content file  supply or override content for detached signature\n");
434        BIO_printf(bio_err, "-to addr       to address\n");
435        BIO_printf(bio_err, "-from ad       from address\n");
436        BIO_printf(bio_err, "-subject s     subject\n");
437        BIO_printf(bio_err,
438                   "-text          include or delete text MIME headers\n");
439        BIO_printf(bio_err,
440                   "-CApath dir    trusted certificates directory\n");
441        BIO_printf(bio_err, "-CAfile file   trusted certificates file\n");
442        BIO_printf(bio_err,
443                   "-no_alt_chains only ever use the first certificate chain found\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    e = setup_engine(bio_err, engine, 0);
463
464    if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
465        BIO_printf(bio_err, "Error getting password\n");
466        goto end;
467    }
468
469    if (need_rand) {
470        app_RAND_load_file(NULL, bio_err, (inrand != NULL));
471        if (inrand != NULL)
472            BIO_printf(bio_err, "%ld semi-random bytes loaded\n",
473                       app_RAND_load_files(inrand));
474    }
475
476    ret = 2;
477
478    if (!(operation & SMIME_SIGNERS))
479        flags &= ~PKCS7_DETACHED;
480
481    if (operation & SMIME_OP) {
482        if (outformat == FORMAT_ASN1)
483            outmode = "wb";
484    } else {
485        if (flags & PKCS7_BINARY)
486            outmode = "wb";
487    }
488
489    if (operation & SMIME_IP) {
490        if (informat == FORMAT_ASN1)
491            inmode = "rb";
492    } else {
493        if (flags & PKCS7_BINARY)
494            inmode = "rb";
495    }
496
497    if (operation == SMIME_ENCRYPT) {
498        if (!cipher) {
499#ifndef OPENSSL_NO_DES
500            cipher = EVP_des_ede3_cbc();
501#else
502            BIO_printf(bio_err, "No cipher selected\n");
503            goto end;
504#endif
505        }
506        encerts = sk_X509_new_null();
507        while (*args) {
508            if (!(cert = load_cert(bio_err, *args, FORMAT_PEM,
509                                   NULL, e, "recipient certificate file"))) {
510#if 0                           /* An appropriate message is already printed */
511                BIO_printf(bio_err,
512                           "Can't read recipient certificate file %s\n",
513                           *args);
514#endif
515                goto end;
516            }
517            sk_X509_push(encerts, cert);
518            cert = NULL;
519            args++;
520        }
521    }
522
523    if (certfile) {
524        if (!(other = load_certs(bio_err, certfile, FORMAT_PEM, NULL,
525                                 e, "certificate file"))) {
526            ERR_print_errors(bio_err);
527            goto end;
528        }
529    }
530
531    if (recipfile && (operation == SMIME_DECRYPT)) {
532        if (!(recip = load_cert(bio_err, recipfile, FORMAT_PEM, NULL,
533                                e, "recipient certificate file"))) {
534            ERR_print_errors(bio_err);
535            goto end;
536        }
537    }
538
539    if (operation == SMIME_DECRYPT) {
540        if (!keyfile)
541            keyfile = recipfile;
542    } else if (operation == SMIME_SIGN) {
543        if (!keyfile)
544            keyfile = signerfile;
545    } else
546        keyfile = NULL;
547
548    if (keyfile) {
549        key = load_key(bio_err, keyfile, keyform, 0, passin, e,
550                       "signing key file");
551        if (!key)
552            goto end;
553    }
554
555    if (infile) {
556        if (!(in = BIO_new_file(infile, inmode))) {
557            BIO_printf(bio_err, "Can't open input file %s\n", infile);
558            goto end;
559        }
560    } else
561        in = BIO_new_fp(stdin, BIO_NOCLOSE);
562
563    if (operation & SMIME_IP) {
564        if (informat == FORMAT_SMIME)
565            p7 = SMIME_read_PKCS7(in, &indata);
566        else if (informat == FORMAT_PEM)
567            p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
568        else if (informat == FORMAT_ASN1)
569            p7 = d2i_PKCS7_bio(in, NULL);
570        else {
571            BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
572            goto end;
573        }
574
575        if (!p7) {
576            BIO_printf(bio_err, "Error reading S/MIME message\n");
577            goto end;
578        }
579        if (contfile) {
580            BIO_free(indata);
581            if (!(indata = BIO_new_file(contfile, "rb"))) {
582                BIO_printf(bio_err, "Can't read content file %s\n", contfile);
583                goto end;
584            }
585        }
586    }
587
588    if (outfile) {
589        if (!(out = BIO_new_file(outfile, outmode))) {
590            BIO_printf(bio_err, "Can't open output file %s\n", outfile);
591            goto end;
592        }
593    } else {
594        out = BIO_new_fp(stdout, BIO_NOCLOSE);
595#ifdef OPENSSL_SYS_VMS
596        {
597            BIO *tmpbio = BIO_new(BIO_f_linebuffer());
598            out = BIO_push(tmpbio, out);
599        }
600#endif
601    }
602
603    if (operation == SMIME_VERIFY) {
604        if (!(store = setup_verify(bio_err, CAfile, CApath)))
605            goto end;
606        X509_STORE_set_verify_cb(store, smime_cb);
607        if (vpm)
608            X509_STORE_set1_param(store, vpm);
609    }
610
611    ret = 3;
612
613    if (operation == SMIME_ENCRYPT) {
614        if (indef)
615            flags |= PKCS7_STREAM;
616        p7 = PKCS7_encrypt(encerts, in, cipher, flags);
617    } else if (operation & SMIME_SIGNERS) {
618        int i;
619        /*
620         * If detached data content we only enable streaming if S/MIME output
621         * format.
622         */
623        if (operation == SMIME_SIGN) {
624            if (flags & PKCS7_DETACHED) {
625                if (outformat == FORMAT_SMIME)
626                    flags |= PKCS7_STREAM;
627            } else if (indef)
628                flags |= PKCS7_STREAM;
629            flags |= PKCS7_PARTIAL;
630            p7 = PKCS7_sign(NULL, NULL, other, in, flags);
631            if (!p7)
632                goto end;
633            if (flags & PKCS7_NOCERTS) {
634                for (i = 0; i < sk_X509_num(other); i++) {
635                    X509 *x = sk_X509_value(other, i);
636                    PKCS7_add_certificate(p7, x);
637                }
638            }
639        } else
640            flags |= PKCS7_REUSE_DIGEST;
641        for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) {
642            signerfile = sk_OPENSSL_STRING_value(sksigners, i);
643            keyfile = sk_OPENSSL_STRING_value(skkeys, i);
644            signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL,
645                               e, "signer certificate");
646            if (!signer)
647                goto end;
648            key = load_key(bio_err, keyfile, keyform, 0, passin, e,
649                           "signing key file");
650            if (!key)
651                goto end;
652            if (!PKCS7_sign_add_signer(p7, signer, key, sign_md, flags))
653                goto end;
654            X509_free(signer);
655            signer = NULL;
656            EVP_PKEY_free(key);
657            key = NULL;
658        }
659        /* If not streaming or resigning finalize structure */
660        if ((operation == SMIME_SIGN) && !(flags & PKCS7_STREAM)) {
661            if (!PKCS7_final(p7, in, flags))
662                goto end;
663        }
664    }
665
666    if (!p7) {
667        BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
668        goto end;
669    }
670
671    ret = 4;
672    if (operation == SMIME_DECRYPT) {
673        if (!PKCS7_decrypt(p7, key, recip, out, flags)) {
674            BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n");
675            goto end;
676        }
677    } else if (operation == SMIME_VERIFY) {
678        STACK_OF(X509) *signers;
679        if (PKCS7_verify(p7, other, store, indata, out, flags))
680            BIO_printf(bio_err, "Verification successful\n");
681        else {
682            BIO_printf(bio_err, "Verification failure\n");
683            goto end;
684        }
685        signers = PKCS7_get0_signers(p7, other, flags);
686        if (!save_certs(signerfile, signers)) {
687            BIO_printf(bio_err, "Error writing signers to %s\n", signerfile);
688            ret = 5;
689            goto end;
690        }
691        sk_X509_free(signers);
692    } else if (operation == SMIME_PK7OUT)
693        PEM_write_bio_PKCS7(out, p7);
694    else {
695        if (to)
696            BIO_printf(out, "To: %s\n", to);
697        if (from)
698            BIO_printf(out, "From: %s\n", from);
699        if (subject)
700            BIO_printf(out, "Subject: %s\n", subject);
701        if (outformat == FORMAT_SMIME) {
702            if (operation == SMIME_RESIGN)
703                SMIME_write_PKCS7(out, p7, indata, flags);
704            else
705                SMIME_write_PKCS7(out, p7, in, flags);
706        } else if (outformat == FORMAT_PEM)
707            PEM_write_bio_PKCS7_stream(out, p7, in, flags);
708        else if (outformat == FORMAT_ASN1)
709            i2d_PKCS7_bio_stream(out, p7, in, flags);
710        else {
711            BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
712            goto end;
713        }
714    }
715    ret = 0;
716 end:
717    if (need_rand)
718        app_RAND_write_file(NULL, bio_err);
719    if (ret)
720        ERR_print_errors(bio_err);
721    sk_X509_pop_free(encerts, X509_free);
722    sk_X509_pop_free(other, X509_free);
723    if (vpm)
724        X509_VERIFY_PARAM_free(vpm);
725    if (sksigners)
726        sk_OPENSSL_STRING_free(sksigners);
727    if (skkeys)
728        sk_OPENSSL_STRING_free(skkeys);
729    X509_STORE_free(store);
730    X509_free(cert);
731    X509_free(recip);
732    X509_free(signer);
733    EVP_PKEY_free(key);
734    PKCS7_free(p7);
735    release_engine(e);
736    BIO_free(in);
737    BIO_free(indata);
738    BIO_free_all(out);
739    if (passin)
740        OPENSSL_free(passin);
741    return (ret);
742}
743
744static int save_certs(char *signerfile, STACK_OF(X509) *signers)
745{
746    int i;
747    BIO *tmp;
748    if (!signerfile)
749        return 1;
750    tmp = BIO_new_file(signerfile, "w");
751    if (!tmp)
752        return 0;
753    for (i = 0; i < sk_X509_num(signers); i++)
754        PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
755    BIO_free(tmp);
756    return 1;
757}
758
759/* Minimal callback just to output policy info (if any) */
760
761static int smime_cb(int ok, X509_STORE_CTX *ctx)
762{
763    int error;
764
765    error = X509_STORE_CTX_get_error(ctx);
766
767    if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
768        && ((error != X509_V_OK) || (ok != 2)))
769        return ok;
770
771    policies_print(NULL, ctx);
772
773    return ok;
774
775}
776