159191Skris/* smime.c */
2296465Sdelphij/*
3296465Sdelphij * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4160814Ssimon * project.
559191Skris */
659191Skris/* ====================================================================
7160814Ssimon * Copyright (c) 1999-2004 The OpenSSL Project.  All rights reserved.
859191Skris *
959191Skris * Redistribution and use in source and binary forms, with or without
1059191Skris * modification, are permitted provided that the following conditions
1159191Skris * are met:
1259191Skris *
1359191Skris * 1. Redistributions of source code must retain the above copyright
14296465Sdelphij *    notice, this list of conditions and the following disclaimer.
1559191Skris *
1659191Skris * 2. Redistributions in binary form must reproduce the above copyright
1759191Skris *    notice, this list of conditions and the following disclaimer in
1859191Skris *    the documentation and/or other materials provided with the
1959191Skris *    distribution.
2059191Skris *
2159191Skris * 3. All advertising materials mentioning features or use of this
2259191Skris *    software must display the following acknowledgment:
2359191Skris *    "This product includes software developed by the OpenSSL Project
2459191Skris *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2559191Skris *
2659191Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2759191Skris *    endorse or promote products derived from this software without
2859191Skris *    prior written permission. For written permission, please contact
2959191Skris *    licensing@OpenSSL.org.
3059191Skris *
3159191Skris * 5. Products derived from this software may not be called "OpenSSL"
3259191Skris *    nor may "OpenSSL" appear in their names without prior written
3359191Skris *    permission of the OpenSSL Project.
3459191Skris *
3559191Skris * 6. Redistributions of any form whatsoever must retain the following
3659191Skris *    acknowledgment:
3759191Skris *    "This product includes software developed by the OpenSSL Project
3859191Skris *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3959191Skris *
4059191Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
4159191Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4259191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4359191Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4459191Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4559191Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4659191Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4759191Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4859191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4959191Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5059191Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
5159191Skris * OF THE POSSIBILITY OF SUCH DAMAGE.
5259191Skris * ====================================================================
5359191Skris *
5459191Skris * This product includes cryptographic software written by Eric Young
5559191Skris * (eay@cryptsoft.com).  This product includes software written by Tim
5659191Skris * Hudson (tjh@cryptsoft.com).
5759191Skris *
5859191Skris */
5959191Skris
6059191Skris/* S/MIME utility function */
6159191Skris
6259191Skris#include <stdio.h>
6359191Skris#include <string.h>
6459191Skris#include "apps.h"
6559191Skris#include <openssl/crypto.h>
6659191Skris#include <openssl/pem.h>
6759191Skris#include <openssl/err.h>
68160814Ssimon#include <openssl/x509_vfy.h>
69160814Ssimon#include <openssl/x509v3.h>
7059191Skris
7159191Skris#undef PROG
7259191Skris#define PROG smime_main
7359191Skrisstatic int save_certs(char *signerfile, STACK_OF(X509) *signers);
74160814Ssimonstatic int smime_cb(int ok, X509_STORE_CTX *ctx);
7559191Skris
76296465Sdelphij#define SMIME_OP        0x10
77296465Sdelphij#define SMIME_ENCRYPT   (1 | SMIME_OP)
78296465Sdelphij#define SMIME_DECRYPT   2
79296465Sdelphij#define SMIME_SIGN      (3 | SMIME_OP)
80296465Sdelphij#define SMIME_VERIFY    4
81296465Sdelphij#define SMIME_PK7OUT    5
8259191Skris
8359191Skrisint MAIN(int, char **);
8459191Skris
8559191Skrisint MAIN(int argc, char **argv)
86296465Sdelphij{
87296465Sdelphij    ENGINE *e = NULL;
88296465Sdelphij    int operation = 0;
89296465Sdelphij    int ret = 0;
90296465Sdelphij    char **args;
91296465Sdelphij    const char *inmode = "r", *outmode = "w";
92296465Sdelphij    char *infile = NULL, *outfile = NULL;
93296465Sdelphij    char *signerfile = NULL, *recipfile = NULL;
94296465Sdelphij    char *certfile = NULL, *keyfile = NULL, *contfile = NULL;
95296465Sdelphij    const EVP_CIPHER *cipher = NULL;
96296465Sdelphij    PKCS7 *p7 = NULL;
97296465Sdelphij    X509_STORE *store = NULL;
98296465Sdelphij    X509 *cert = NULL, *recip = NULL, *signer = NULL;
99296465Sdelphij    EVP_PKEY *key = NULL;
100296465Sdelphij    STACK_OF(X509) *encerts = NULL, *other = NULL;
101296465Sdelphij    BIO *in = NULL, *out = NULL, *indata = NULL;
102296465Sdelphij    int badarg = 0;
103296465Sdelphij    int flags = PKCS7_DETACHED;
104296465Sdelphij    char *to = NULL, *from = NULL, *subject = NULL;
105296465Sdelphij    char *CAfile = NULL, *CApath = NULL;
106296465Sdelphij    char *passargin = NULL, *passin = NULL;
107296465Sdelphij    char *inrand = NULL;
108296465Sdelphij    int need_rand = 0;
109296465Sdelphij    int informat = FORMAT_SMIME, outformat = FORMAT_SMIME;
110296465Sdelphij    int keyform = FORMAT_PEM;
111111147Snectar#ifndef OPENSSL_NO_ENGINE
112296465Sdelphij    char *engine = NULL;
113111147Snectar#endif
114109998Smarkm
115296465Sdelphij    X509_VERIFY_PARAM *vpm = NULL;
116160814Ssimon
117296465Sdelphij    args = argv + 1;
118296465Sdelphij    ret = 1;
11959191Skris
120296465Sdelphij    apps_startup();
121109998Smarkm
122296465Sdelphij    if (bio_err == NULL) {
123296465Sdelphij        if ((bio_err = BIO_new(BIO_s_file())) != NULL)
124296465Sdelphij            BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
125296465Sdelphij    }
126109998Smarkm
127296465Sdelphij    if (!load_config(bio_err, NULL))
128296465Sdelphij        goto end;
129109998Smarkm
130296465Sdelphij    while (!badarg && *args && *args[0] == '-') {
131296465Sdelphij        if (!strcmp(*args, "-encrypt"))
132296465Sdelphij            operation = SMIME_ENCRYPT;
133296465Sdelphij        else if (!strcmp(*args, "-decrypt"))
134296465Sdelphij            operation = SMIME_DECRYPT;
135296465Sdelphij        else if (!strcmp(*args, "-sign"))
136296465Sdelphij            operation = SMIME_SIGN;
137296465Sdelphij        else if (!strcmp(*args, "-verify"))
138296465Sdelphij            operation = SMIME_VERIFY;
139296465Sdelphij        else if (!strcmp(*args, "-pk7out"))
140296465Sdelphij            operation = SMIME_PK7OUT;
141109998Smarkm#ifndef OPENSSL_NO_DES
142296465Sdelphij        else if (!strcmp(*args, "-des3"))
143296465Sdelphij            cipher = EVP_des_ede3_cbc();
144296465Sdelphij        else if (!strcmp(*args, "-des"))
145296465Sdelphij            cipher = EVP_des_cbc();
14659191Skris#endif
147194206Ssimon#ifndef OPENSSL_NO_SEED
148296465Sdelphij        else if (!strcmp(*args, "-seed"))
149296465Sdelphij            cipher = EVP_seed_cbc();
150194206Ssimon#endif
151109998Smarkm#ifndef OPENSSL_NO_RC2
152296465Sdelphij        else if (!strcmp(*args, "-rc2-40"))
153296465Sdelphij            cipher = EVP_rc2_40_cbc();
154296465Sdelphij        else if (!strcmp(*args, "-rc2-128"))
155296465Sdelphij            cipher = EVP_rc2_cbc();
156296465Sdelphij        else if (!strcmp(*args, "-rc2-64"))
157296465Sdelphij            cipher = EVP_rc2_64_cbc();
15859191Skris#endif
159109998Smarkm#ifndef OPENSSL_NO_AES
160296465Sdelphij        else if (!strcmp(*args, "-aes128"))
161296465Sdelphij            cipher = EVP_aes_128_cbc();
162296465Sdelphij        else if (!strcmp(*args, "-aes192"))
163296465Sdelphij            cipher = EVP_aes_192_cbc();
164296465Sdelphij        else if (!strcmp(*args, "-aes256"))
165296465Sdelphij            cipher = EVP_aes_256_cbc();
166109998Smarkm#endif
167162911Ssimon#ifndef OPENSSL_NO_CAMELLIA
168296465Sdelphij        else if (!strcmp(*args, "-camellia128"))
169296465Sdelphij            cipher = EVP_camellia_128_cbc();
170296465Sdelphij        else if (!strcmp(*args, "-camellia192"))
171296465Sdelphij            cipher = EVP_camellia_192_cbc();
172296465Sdelphij        else if (!strcmp(*args, "-camellia256"))
173296465Sdelphij            cipher = EVP_camellia_256_cbc();
174162911Ssimon#endif
175296465Sdelphij        else if (!strcmp(*args, "-text"))
176296465Sdelphij            flags |= PKCS7_TEXT;
177296465Sdelphij        else if (!strcmp(*args, "-nointern"))
178296465Sdelphij            flags |= PKCS7_NOINTERN;
179296465Sdelphij        else if (!strcmp(*args, "-noverify"))
180296465Sdelphij            flags |= PKCS7_NOVERIFY;
181296465Sdelphij        else if (!strcmp(*args, "-nochain"))
182296465Sdelphij            flags |= PKCS7_NOCHAIN;
183296465Sdelphij        else if (!strcmp(*args, "-nocerts"))
184296465Sdelphij            flags |= PKCS7_NOCERTS;
185296465Sdelphij        else if (!strcmp(*args, "-noattr"))
186296465Sdelphij            flags |= PKCS7_NOATTR;
187296465Sdelphij        else if (!strcmp(*args, "-nodetach"))
188296465Sdelphij            flags &= ~PKCS7_DETACHED;
189296465Sdelphij        else if (!strcmp(*args, "-nosmimecap"))
190296465Sdelphij            flags |= PKCS7_NOSMIMECAP;
191296465Sdelphij        else if (!strcmp(*args, "-binary"))
192296465Sdelphij            flags |= PKCS7_BINARY;
193296465Sdelphij        else if (!strcmp(*args, "-nosigs"))
194296465Sdelphij            flags |= PKCS7_NOSIGS;
195296465Sdelphij        else if (!strcmp(*args, "-nooldmime"))
196296465Sdelphij            flags |= PKCS7_NOOLDMIMETYPE;
197296465Sdelphij        else if (!strcmp(*args, "-crlfeol"))
198296465Sdelphij            flags |= PKCS7_CRLFEOL;
199296465Sdelphij        else if (!strcmp(*args, "-rand")) {
200296465Sdelphij            if (args[1]) {
201296465Sdelphij                args++;
202296465Sdelphij                inrand = *args;
203296465Sdelphij            } else
204296465Sdelphij                badarg = 1;
205296465Sdelphij            need_rand = 1;
206296465Sdelphij        }
207111147Snectar#ifndef OPENSSL_NO_ENGINE
208296465Sdelphij        else if (!strcmp(*args, "-engine")) {
209296465Sdelphij            if (args[1]) {
210296465Sdelphij                args++;
211296465Sdelphij                engine = *args;
212296465Sdelphij            } else
213296465Sdelphij                badarg = 1;
214296465Sdelphij        }
215111147Snectar#endif
216296465Sdelphij        else if (!strcmp(*args, "-passin")) {
217296465Sdelphij            if (args[1]) {
218296465Sdelphij                args++;
219296465Sdelphij                passargin = *args;
220296465Sdelphij            } else
221296465Sdelphij                badarg = 1;
222296465Sdelphij        } else if (!strcmp(*args, "-to")) {
223296465Sdelphij            if (args[1]) {
224296465Sdelphij                args++;
225296465Sdelphij                to = *args;
226296465Sdelphij            } else
227296465Sdelphij                badarg = 1;
228296465Sdelphij        } else if (!strcmp(*args, "-from")) {
229296465Sdelphij            if (args[1]) {
230296465Sdelphij                args++;
231296465Sdelphij                from = *args;
232296465Sdelphij            } else
233296465Sdelphij                badarg = 1;
234296465Sdelphij        } else if (!strcmp(*args, "-subject")) {
235296465Sdelphij            if (args[1]) {
236296465Sdelphij                args++;
237296465Sdelphij                subject = *args;
238296465Sdelphij            } else
239296465Sdelphij                badarg = 1;
240296465Sdelphij        } else if (!strcmp(*args, "-signer")) {
241296465Sdelphij            if (args[1]) {
242296465Sdelphij                args++;
243296465Sdelphij                signerfile = *args;
244296465Sdelphij            } else
245296465Sdelphij                badarg = 1;
246296465Sdelphij        } else if (!strcmp(*args, "-recip")) {
247296465Sdelphij            if (args[1]) {
248296465Sdelphij                args++;
249296465Sdelphij                recipfile = *args;
250296465Sdelphij            } else
251296465Sdelphij                badarg = 1;
252296465Sdelphij        } else if (!strcmp(*args, "-inkey")) {
253296465Sdelphij            if (args[1]) {
254296465Sdelphij                args++;
255296465Sdelphij                keyfile = *args;
256296465Sdelphij            } else
257296465Sdelphij                badarg = 1;
258296465Sdelphij        } else if (!strcmp(*args, "-keyform")) {
259296465Sdelphij            if (args[1]) {
260296465Sdelphij                args++;
261296465Sdelphij                keyform = str2fmt(*args);
262296465Sdelphij            } else
263296465Sdelphij                badarg = 1;
264296465Sdelphij        } else if (!strcmp(*args, "-certfile")) {
265296465Sdelphij            if (args[1]) {
266296465Sdelphij                args++;
267296465Sdelphij                certfile = *args;
268296465Sdelphij            } else
269296465Sdelphij                badarg = 1;
270296465Sdelphij        } else if (!strcmp(*args, "-CAfile")) {
271296465Sdelphij            if (args[1]) {
272296465Sdelphij                args++;
273296465Sdelphij                CAfile = *args;
274296465Sdelphij            } else
275296465Sdelphij                badarg = 1;
276296465Sdelphij        } else if (!strcmp(*args, "-CApath")) {
277296465Sdelphij            if (args[1]) {
278296465Sdelphij                args++;
279296465Sdelphij                CApath = *args;
280296465Sdelphij            } else
281296465Sdelphij                badarg = 1;
282296465Sdelphij        } else if (!strcmp(*args, "-in")) {
283296465Sdelphij            if (args[1]) {
284296465Sdelphij                args++;
285296465Sdelphij                infile = *args;
286296465Sdelphij            } else
287296465Sdelphij                badarg = 1;
288296465Sdelphij        } else if (!strcmp(*args, "-inform")) {
289296465Sdelphij            if (args[1]) {
290296465Sdelphij                args++;
291296465Sdelphij                informat = str2fmt(*args);
292296465Sdelphij            } else
293296465Sdelphij                badarg = 1;
294296465Sdelphij        } else if (!strcmp(*args, "-outform")) {
295296465Sdelphij            if (args[1]) {
296296465Sdelphij                args++;
297296465Sdelphij                outformat = str2fmt(*args);
298296465Sdelphij            } else
299296465Sdelphij                badarg = 1;
300296465Sdelphij        } else if (!strcmp(*args, "-out")) {
301296465Sdelphij            if (args[1]) {
302296465Sdelphij                args++;
303296465Sdelphij                outfile = *args;
304296465Sdelphij            } else
305296465Sdelphij                badarg = 1;
306296465Sdelphij        } else if (!strcmp(*args, "-content")) {
307296465Sdelphij            if (args[1]) {
308296465Sdelphij                args++;
309296465Sdelphij                contfile = *args;
310296465Sdelphij            } else
311296465Sdelphij                badarg = 1;
312296465Sdelphij        } else if (args_verify(&args, NULL, &badarg, bio_err, &vpm))
313296465Sdelphij            continue;
314296465Sdelphij        else
315296465Sdelphij            badarg = 1;
316296465Sdelphij        args++;
317296465Sdelphij    }
31859191Skris
319296465Sdelphij    if (operation == SMIME_SIGN) {
320296465Sdelphij        if (!signerfile) {
321296465Sdelphij            BIO_printf(bio_err, "No signer certificate specified\n");
322296465Sdelphij            badarg = 1;
323296465Sdelphij        }
324296465Sdelphij        need_rand = 1;
325296465Sdelphij    } else if (operation == SMIME_DECRYPT) {
326296465Sdelphij        if (!recipfile && !keyfile) {
327296465Sdelphij            BIO_printf(bio_err,
328296465Sdelphij                       "No recipient certificate or key specified\n");
329296465Sdelphij            badarg = 1;
330296465Sdelphij        }
331296465Sdelphij    } else if (operation == SMIME_ENCRYPT) {
332296465Sdelphij        if (!*args) {
333296465Sdelphij            BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
334296465Sdelphij            badarg = 1;
335296465Sdelphij        }
336296465Sdelphij        need_rand = 1;
337296465Sdelphij    } else if (!operation)
338296465Sdelphij        badarg = 1;
339160814Ssimon
340296465Sdelphij    if (badarg) {
341296465Sdelphij        BIO_printf(bio_err, "Usage smime [options] cert.pem ...\n");
342296465Sdelphij        BIO_printf(bio_err, "where options are\n");
343296465Sdelphij        BIO_printf(bio_err, "-encrypt       encrypt message\n");
344296465Sdelphij        BIO_printf(bio_err, "-decrypt       decrypt encrypted message\n");
345296465Sdelphij        BIO_printf(bio_err, "-sign          sign message\n");
346296465Sdelphij        BIO_printf(bio_err, "-verify        verify signed message\n");
347296465Sdelphij        BIO_printf(bio_err, "-pk7out        output PKCS#7 structure\n");
348109998Smarkm#ifndef OPENSSL_NO_DES
349296465Sdelphij        BIO_printf(bio_err, "-des3          encrypt with triple DES\n");
350296465Sdelphij        BIO_printf(bio_err, "-des           encrypt with DES\n");
35159191Skris#endif
352194206Ssimon#ifndef OPENSSL_NO_SEED
353296465Sdelphij        BIO_printf(bio_err, "-seed          encrypt with SEED\n");
354194206Ssimon#endif
355109998Smarkm#ifndef OPENSSL_NO_RC2
356296465Sdelphij        BIO_printf(bio_err, "-rc2-40        encrypt with RC2-40 (default)\n");
357296465Sdelphij        BIO_printf(bio_err, "-rc2-64        encrypt with RC2-64\n");
358296465Sdelphij        BIO_printf(bio_err, "-rc2-128       encrypt with RC2-128\n");
35959191Skris#endif
360109998Smarkm#ifndef OPENSSL_NO_AES
361296465Sdelphij        BIO_printf(bio_err, "-aes128, -aes192, -aes256\n");
362296465Sdelphij        BIO_printf(bio_err,
363296465Sdelphij                   "               encrypt PEM output with cbc aes\n");
364109998Smarkm#endif
365162911Ssimon#ifndef OPENSSL_NO_CAMELLIA
366296465Sdelphij        BIO_printf(bio_err, "-camellia128, -camellia192, -camellia256\n");
367296465Sdelphij        BIO_printf(bio_err,
368296465Sdelphij                   "               encrypt PEM output with cbc camellia\n");
369162911Ssimon#endif
370296465Sdelphij        BIO_printf(bio_err,
371296465Sdelphij                   "-nointern      don't search certificates in message for signer\n");
372296465Sdelphij        BIO_printf(bio_err,
373296465Sdelphij                   "-nosigs        don't verify message signature\n");
374296465Sdelphij        BIO_printf(bio_err,
375296465Sdelphij                   "-noverify      don't verify signers certificate\n");
376296465Sdelphij        BIO_printf(bio_err,
377296465Sdelphij                   "-nocerts       don't include signers certificate when signing\n");
378296465Sdelphij        BIO_printf(bio_err, "-nodetach      use opaque signing\n");
379296465Sdelphij        BIO_printf(bio_err,
380296465Sdelphij                   "-noattr        don't include any signed attributes\n");
381296465Sdelphij        BIO_printf(bio_err,
382296465Sdelphij                   "-binary        don't translate message to text\n");
383296465Sdelphij        BIO_printf(bio_err, "-certfile file other certificates file\n");
384296465Sdelphij        BIO_printf(bio_err, "-signer file   signer certificate file\n");
385296465Sdelphij        BIO_printf(bio_err,
386296465Sdelphij                   "-recip  file   recipient certificate file for decryption\n");
387296465Sdelphij        BIO_printf(bio_err, "-in file       input file\n");
388296465Sdelphij        BIO_printf(bio_err,
389296465Sdelphij                   "-inform arg    input format SMIME (default), PEM or DER\n");
390296465Sdelphij        BIO_printf(bio_err,
391296465Sdelphij                   "-inkey file    input private key (if not signer or recipient)\n");
392296465Sdelphij        BIO_printf(bio_err,
393296465Sdelphij                   "-keyform arg   input private key format (PEM or ENGINE)\n");
394296465Sdelphij        BIO_printf(bio_err, "-out file      output file\n");
395296465Sdelphij        BIO_printf(bio_err,
396296465Sdelphij                   "-outform arg   output format SMIME (default), PEM or DER\n");
397296465Sdelphij        BIO_printf(bio_err,
398296465Sdelphij                   "-content file  supply or override content for detached signature\n");
399296465Sdelphij        BIO_printf(bio_err, "-to addr       to address\n");
400296465Sdelphij        BIO_printf(bio_err, "-from ad       from address\n");
401296465Sdelphij        BIO_printf(bio_err, "-subject s     subject\n");
402296465Sdelphij        BIO_printf(bio_err,
403296465Sdelphij                   "-text          include or delete text MIME headers\n");
404296465Sdelphij        BIO_printf(bio_err,
405296465Sdelphij                   "-CApath dir    trusted certificates directory\n");
406296465Sdelphij        BIO_printf(bio_err, "-CAfile file   trusted certificates file\n");
407296465Sdelphij        BIO_printf(bio_err,
408296465Sdelphij                   "-crl_check     check revocation status of signer's certificate using CRLs\n");
409296465Sdelphij        BIO_printf(bio_err,
410296465Sdelphij                   "-crl_check_all check revocation status of signer's certificate chain using CRLs\n");
411111147Snectar#ifndef OPENSSL_NO_ENGINE
412296465Sdelphij        BIO_printf(bio_err,
413296465Sdelphij                   "-engine e      use engine e, possibly a hardware device.\n");
414111147Snectar#endif
415296465Sdelphij        BIO_printf(bio_err, "-passin arg    input file pass phrase source\n");
416296465Sdelphij        BIO_printf(bio_err, "-rand file%cfile%c...\n", LIST_SEPARATOR_CHAR,
417296465Sdelphij                   LIST_SEPARATOR_CHAR);
418296465Sdelphij        BIO_printf(bio_err,
419296465Sdelphij                   "               load the file (or the files in the directory) into\n");
420296465Sdelphij        BIO_printf(bio_err, "               the random number generator\n");
421296465Sdelphij        BIO_printf(bio_err,
422296465Sdelphij                   "cert.pem       recipient certificate(s) for encryption\n");
423296465Sdelphij        goto end;
424296465Sdelphij    }
425111147Snectar#ifndef OPENSSL_NO_ENGINE
426296465Sdelphij    e = setup_engine(bio_err, engine, 0);
427111147Snectar#endif
428109998Smarkm
429296465Sdelphij    if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
430296465Sdelphij        BIO_printf(bio_err, "Error getting password\n");
431296465Sdelphij        goto end;
432296465Sdelphij    }
43359191Skris
434296465Sdelphij    if (need_rand) {
435296465Sdelphij        app_RAND_load_file(NULL, bio_err, (inrand != NULL));
436296465Sdelphij        if (inrand != NULL)
437296465Sdelphij            BIO_printf(bio_err, "%ld semi-random bytes loaded\n",
438296465Sdelphij                       app_RAND_load_files(inrand));
439296465Sdelphij    }
44059191Skris
441296465Sdelphij    ret = 2;
44259191Skris
443296465Sdelphij    if (operation != SMIME_SIGN)
444296465Sdelphij        flags &= ~PKCS7_DETACHED;
44559191Skris
446296465Sdelphij    if (operation & SMIME_OP) {
447296465Sdelphij        if (flags & PKCS7_BINARY)
448296465Sdelphij            inmode = "rb";
449296465Sdelphij        if (outformat == FORMAT_ASN1)
450296465Sdelphij            outmode = "wb";
451296465Sdelphij    } else {
452296465Sdelphij        if (flags & PKCS7_BINARY)
453296465Sdelphij            outmode = "wb";
454296465Sdelphij        if (informat == FORMAT_ASN1)
455296465Sdelphij            inmode = "rb";
456296465Sdelphij    }
45759191Skris
458296465Sdelphij    if (operation == SMIME_ENCRYPT) {
459296465Sdelphij        if (!cipher) {
460296465Sdelphij#ifndef OPENSSL_NO_DES
461296465Sdelphij            cipher = EVP_des_ede3_cbc();
46259191Skris#else
463296465Sdelphij            BIO_printf(bio_err, "No cipher selected\n");
464296465Sdelphij            goto end;
46559191Skris#endif
466296465Sdelphij        }
467296465Sdelphij        encerts = sk_X509_new_null();
468296465Sdelphij        while (*args) {
469296465Sdelphij            if (!(cert = load_cert(bio_err, *args, FORMAT_PEM,
470296465Sdelphij                                   NULL, e, "recipient certificate file"))) {
471296465Sdelphij#if 0                           /* An appropriate message is already printed */
472296465Sdelphij                BIO_printf(bio_err,
473296465Sdelphij                           "Can't read recipient certificate file %s\n",
474296465Sdelphij                           *args);
475109998Smarkm#endif
476296465Sdelphij                goto end;
477296465Sdelphij            }
478296465Sdelphij            sk_X509_push(encerts, cert);
479296465Sdelphij            cert = NULL;
480296465Sdelphij            args++;
481296465Sdelphij        }
482296465Sdelphij    }
48359191Skris
484296465Sdelphij    if (signerfile && (operation == SMIME_SIGN)) {
485296465Sdelphij        if (!(signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL,
486296465Sdelphij                                 e, "signer certificate"))) {
487296465Sdelphij#if 0                           /* An appropri message has already been
488296465Sdelphij                                 * printed */
489296465Sdelphij            BIO_printf(bio_err, "Can't read signer certificate file %s\n",
490296465Sdelphij                       signerfile);
491109998Smarkm#endif
492296465Sdelphij            goto end;
493296465Sdelphij        }
494296465Sdelphij    }
49559191Skris
496296465Sdelphij    if (certfile) {
497296465Sdelphij        if (!(other = load_certs(bio_err, certfile, FORMAT_PEM, NULL,
498296465Sdelphij                                 e, "certificate file"))) {
499296465Sdelphij#if 0                           /* An appropriate message has already been
500296465Sdelphij                                 * printed */
501296465Sdelphij            BIO_printf(bio_err, "Can't read certificate file %s\n", certfile);
502109998Smarkm#endif
503296465Sdelphij            ERR_print_errors(bio_err);
504296465Sdelphij            goto end;
505296465Sdelphij        }
506296465Sdelphij    }
50759191Skris
508296465Sdelphij    if (recipfile && (operation == SMIME_DECRYPT)) {
509296465Sdelphij        if (!(recip = load_cert(bio_err, recipfile, FORMAT_PEM, NULL,
510296465Sdelphij                                e, "recipient certificate file"))) {
511296465Sdelphij#if 0                           /* An appropriate message has alrady been
512296465Sdelphij                                 * printed */
513296465Sdelphij            BIO_printf(bio_err, "Can't read recipient certificate file %s\n",
514296465Sdelphij                       recipfile);
515109998Smarkm#endif
516296465Sdelphij            ERR_print_errors(bio_err);
517296465Sdelphij            goto end;
518296465Sdelphij        }
519296465Sdelphij    }
52059191Skris
521296465Sdelphij    if (operation == SMIME_DECRYPT) {
522296465Sdelphij        if (!keyfile)
523296465Sdelphij            keyfile = recipfile;
524296465Sdelphij    } else if (operation == SMIME_SIGN) {
525296465Sdelphij        if (!keyfile)
526296465Sdelphij            keyfile = signerfile;
527296465Sdelphij    } else
528296465Sdelphij        keyfile = NULL;
52959191Skris
530296465Sdelphij    if (keyfile) {
531296465Sdelphij        key = load_key(bio_err, keyfile, keyform, 0, passin, e,
532296465Sdelphij                       "signing key file");
533296465Sdelphij        if (!key)
534296465Sdelphij            goto end;
535296465Sdelphij    }
53659191Skris
537296465Sdelphij    if (infile) {
538296465Sdelphij        if (!(in = BIO_new_file(infile, inmode))) {
539296465Sdelphij            BIO_printf(bio_err, "Can't open input file %s\n", infile);
540296465Sdelphij            goto end;
541296465Sdelphij        }
542296465Sdelphij    } else
543296465Sdelphij        in = BIO_new_fp(stdin, BIO_NOCLOSE);
54459191Skris
545296465Sdelphij    if (outfile) {
546296465Sdelphij        if (!(out = BIO_new_file(outfile, outmode))) {
547296465Sdelphij            BIO_printf(bio_err, "Can't open output file %s\n", outfile);
548296465Sdelphij            goto end;
549296465Sdelphij        }
550296465Sdelphij    } else {
551296465Sdelphij        out = BIO_new_fp(stdout, BIO_NOCLOSE);
552109998Smarkm#ifdef OPENSSL_SYS_VMS
553296465Sdelphij        {
554296465Sdelphij            BIO *tmpbio = BIO_new(BIO_f_linebuffer());
555296465Sdelphij            out = BIO_push(tmpbio, out);
556296465Sdelphij        }
55768651Skris#endif
558296465Sdelphij    }
55959191Skris
560296465Sdelphij    if (operation == SMIME_VERIFY) {
561296465Sdelphij        if (!(store = setup_verify(bio_err, CAfile, CApath)))
562296465Sdelphij            goto end;
563296465Sdelphij        X509_STORE_set_verify_cb_func(store, smime_cb);
564296465Sdelphij        if (vpm)
565296465Sdelphij            X509_STORE_set1_param(store, vpm);
566296465Sdelphij    }
56759191Skris
568296465Sdelphij    ret = 3;
569109998Smarkm
570296465Sdelphij    if (operation == SMIME_ENCRYPT)
571296465Sdelphij        p7 = PKCS7_encrypt(encerts, in, cipher, flags);
572296465Sdelphij    else if (operation == SMIME_SIGN) {
573296465Sdelphij        /*
574296465Sdelphij         * If detached data and SMIME output enable partial signing.
575296465Sdelphij         */
576296465Sdelphij        if ((flags & PKCS7_DETACHED) && (outformat == FORMAT_SMIME))
577296465Sdelphij            flags |= PKCS7_STREAM;
578296465Sdelphij        p7 = PKCS7_sign(signer, key, other, in, flags);
579296465Sdelphij    } else {
580296465Sdelphij        if (informat == FORMAT_SMIME)
581296465Sdelphij            p7 = SMIME_read_PKCS7(in, &indata);
582296465Sdelphij        else if (informat == FORMAT_PEM)
583296465Sdelphij            p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
584296465Sdelphij        else if (informat == FORMAT_ASN1)
585296465Sdelphij            p7 = d2i_PKCS7_bio(in, NULL);
586296465Sdelphij        else {
587296465Sdelphij            BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
588296465Sdelphij            goto end;
589296465Sdelphij        }
59059191Skris
591296465Sdelphij        if (!p7) {
592296465Sdelphij            BIO_printf(bio_err, "Error reading S/MIME message\n");
593296465Sdelphij            goto end;
594296465Sdelphij        }
595296465Sdelphij        if (contfile) {
596296465Sdelphij            BIO_free(indata);
597296465Sdelphij            if (!(indata = BIO_new_file(contfile, "rb"))) {
598296465Sdelphij                BIO_printf(bio_err, "Can't read content file %s\n", contfile);
599296465Sdelphij                goto end;
600296465Sdelphij            }
601296465Sdelphij        }
602296465Sdelphij    }
60368651Skris
604296465Sdelphij    if (!p7) {
605296465Sdelphij        BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
606296465Sdelphij        goto end;
607296465Sdelphij    }
60859191Skris
609296465Sdelphij    ret = 4;
610296465Sdelphij    if (operation == SMIME_DECRYPT) {
611296465Sdelphij        if (!PKCS7_decrypt(p7, key, recip, out, flags)) {
612296465Sdelphij            BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n");
613296465Sdelphij            goto end;
614296465Sdelphij        }
615296465Sdelphij    } else if (operation == SMIME_VERIFY) {
616296465Sdelphij        STACK_OF(X509) *signers;
617296465Sdelphij        if (PKCS7_verify(p7, other, store, indata, out, flags))
618296465Sdelphij            BIO_printf(bio_err, "Verification successful\n");
619296465Sdelphij        else {
620296465Sdelphij            BIO_printf(bio_err, "Verification failure\n");
621296465Sdelphij            goto end;
622296465Sdelphij        }
623296465Sdelphij        signers = PKCS7_get0_signers(p7, other, flags);
624296465Sdelphij        if (!save_certs(signerfile, signers)) {
625296465Sdelphij            BIO_printf(bio_err, "Error writing signers to %s\n", signerfile);
626296465Sdelphij            ret = 5;
627296465Sdelphij            goto end;
628296465Sdelphij        }
629296465Sdelphij        sk_X509_free(signers);
630296465Sdelphij    } else if (operation == SMIME_PK7OUT)
631296465Sdelphij        PEM_write_bio_PKCS7(out, p7);
632296465Sdelphij    else {
633296465Sdelphij        if (to)
634296465Sdelphij            BIO_printf(out, "To: %s\n", to);
635296465Sdelphij        if (from)
636296465Sdelphij            BIO_printf(out, "From: %s\n", from);
637296465Sdelphij        if (subject)
638296465Sdelphij            BIO_printf(out, "Subject: %s\n", subject);
639296465Sdelphij        if (outformat == FORMAT_SMIME)
640296465Sdelphij            SMIME_write_PKCS7(out, p7, in, flags);
641296465Sdelphij        else if (outformat == FORMAT_PEM)
642296465Sdelphij            PEM_write_bio_PKCS7(out, p7);
643296465Sdelphij        else if (outformat == FORMAT_ASN1)
644296465Sdelphij            i2d_PKCS7_bio(out, p7);
645296465Sdelphij        else {
646296465Sdelphij            BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
647296465Sdelphij            goto end;
648296465Sdelphij        }
649296465Sdelphij    }
650296465Sdelphij    ret = 0;
651296465Sdelphij end:
652296465Sdelphij    if (need_rand)
653296465Sdelphij        app_RAND_write_file(NULL, bio_err);
654296465Sdelphij    if (ret)
655296465Sdelphij        ERR_print_errors(bio_err);
656296465Sdelphij    sk_X509_pop_free(encerts, X509_free);
657296465Sdelphij    sk_X509_pop_free(other, X509_free);
658296465Sdelphij    if (vpm)
659296465Sdelphij        X509_VERIFY_PARAM_free(vpm);
660296465Sdelphij    X509_STORE_free(store);
661296465Sdelphij    X509_free(cert);
662296465Sdelphij    X509_free(recip);
663296465Sdelphij    X509_free(signer);
664296465Sdelphij    EVP_PKEY_free(key);
665296465Sdelphij    PKCS7_free(p7);
666296465Sdelphij    BIO_free(in);
667296465Sdelphij    BIO_free(indata);
668296465Sdelphij    BIO_free_all(out);
669296465Sdelphij    if (passin)
670296465Sdelphij        OPENSSL_free(passin);
671296465Sdelphij    return (ret);
67259191Skris}
67359191Skris
67459191Skrisstatic int save_certs(char *signerfile, STACK_OF(X509) *signers)
675296465Sdelphij{
676296465Sdelphij    int i;
677296465Sdelphij    BIO *tmp;
678296465Sdelphij    if (!signerfile)
679296465Sdelphij        return 1;
680296465Sdelphij    tmp = BIO_new_file(signerfile, "w");
681296465Sdelphij    if (!tmp)
682296465Sdelphij        return 0;
683296465Sdelphij    for (i = 0; i < sk_X509_num(signers); i++)
684296465Sdelphij        PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
685296465Sdelphij    BIO_free(tmp);
686296465Sdelphij    return 1;
687296465Sdelphij}
688160814Ssimon
689160814Ssimon/* Minimal callback just to output policy info (if any) */
690160814Ssimon
691160814Ssimonstatic int smime_cb(int ok, X509_STORE_CTX *ctx)
692296465Sdelphij{
693296465Sdelphij    int error;
694160814Ssimon
695296465Sdelphij    error = X509_STORE_CTX_get_error(ctx);
696160814Ssimon
697296465Sdelphij    if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
698296465Sdelphij        && ((error != X509_V_OK) || (ok != 2)))
699296465Sdelphij        return ok;
700160814Ssimon
701296465Sdelphij    policies_print(NULL, ctx);
702160814Ssimon
703296465Sdelphij    return ok;
704160814Ssimon
705296465Sdelphij}
706