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