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