159191Skris/* smime.c */
2280304Sjkim/*
3280304Sjkim * 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
14280304Sjkim *    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
76280304Sjkim#define SMIME_OP        0x10
77280304Sjkim#define SMIME_IP        0x20
78280304Sjkim#define SMIME_SIGNERS   0x40
79280304Sjkim#define SMIME_ENCRYPT   (1 | SMIME_OP)
80280304Sjkim#define SMIME_DECRYPT   (2 | SMIME_IP)
81280304Sjkim#define SMIME_SIGN      (3 | SMIME_OP | SMIME_SIGNERS)
82280304Sjkim#define SMIME_VERIFY    (4 | SMIME_IP)
83280304Sjkim#define SMIME_PK7OUT    (5 | SMIME_IP | SMIME_OP)
84280304Sjkim#define SMIME_RESIGN    (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
8559191Skris
8659191Skrisint MAIN(int, char **);
8759191Skris
8859191Skrisint MAIN(int argc, char **argv)
89280304Sjkim{
90280304Sjkim    ENGINE *e = NULL;
91280304Sjkim    int operation = 0;
92280304Sjkim    int ret = 0;
93280304Sjkim    char **args;
94280304Sjkim    const char *inmode = "r", *outmode = "w";
95280304Sjkim    char *infile = NULL, *outfile = NULL;
96280304Sjkim    char *signerfile = NULL, *recipfile = NULL;
97280304Sjkim    STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL;
98280304Sjkim    char *certfile = NULL, *keyfile = NULL, *contfile = NULL;
99280304Sjkim    const EVP_CIPHER *cipher = NULL;
100280304Sjkim    PKCS7 *p7 = NULL;
101280304Sjkim    X509_STORE *store = NULL;
102280304Sjkim    X509 *cert = NULL, *recip = NULL, *signer = NULL;
103280304Sjkim    EVP_PKEY *key = NULL;
104280304Sjkim    STACK_OF(X509) *encerts = NULL, *other = NULL;
105280304Sjkim    BIO *in = NULL, *out = NULL, *indata = NULL;
106280304Sjkim    int badarg = 0;
107280304Sjkim    int flags = PKCS7_DETACHED;
108280304Sjkim    char *to = NULL, *from = NULL, *subject = NULL;
109280304Sjkim    char *CAfile = NULL, *CApath = NULL;
110280304Sjkim    char *passargin = NULL, *passin = NULL;
111280304Sjkim    char *inrand = NULL;
112280304Sjkim    int need_rand = 0;
113280304Sjkim    int indef = 0;
114280304Sjkim    const EVP_MD *sign_md = NULL;
115280304Sjkim    int informat = FORMAT_SMIME, outformat = FORMAT_SMIME;
116280304Sjkim    int keyform = FORMAT_PEM;
117111147Snectar#ifndef OPENSSL_NO_ENGINE
118280304Sjkim    char *engine = NULL;
119111147Snectar#endif
120109998Smarkm
121280304Sjkim    X509_VERIFY_PARAM *vpm = NULL;
122160814Ssimon
123280304Sjkim    args = argv + 1;
124280304Sjkim    ret = 1;
12559191Skris
126280304Sjkim    apps_startup();
127109998Smarkm
128280304Sjkim    if (bio_err == NULL) {
129280304Sjkim        if ((bio_err = BIO_new(BIO_s_file())) != NULL)
130280304Sjkim            BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
131280304Sjkim    }
132109998Smarkm
133280304Sjkim    if (!load_config(bio_err, NULL))
134280304Sjkim        goto end;
135109998Smarkm
136280304Sjkim    while (!badarg && *args && *args[0] == '-') {
137280304Sjkim        if (!strcmp(*args, "-encrypt"))
138280304Sjkim            operation = SMIME_ENCRYPT;
139280304Sjkim        else if (!strcmp(*args, "-decrypt"))
140280304Sjkim            operation = SMIME_DECRYPT;
141280304Sjkim        else if (!strcmp(*args, "-sign"))
142280304Sjkim            operation = SMIME_SIGN;
143280304Sjkim        else if (!strcmp(*args, "-resign"))
144280304Sjkim            operation = SMIME_RESIGN;
145280304Sjkim        else if (!strcmp(*args, "-verify"))
146280304Sjkim            operation = SMIME_VERIFY;
147280304Sjkim        else if (!strcmp(*args, "-pk7out"))
148280304Sjkim            operation = SMIME_PK7OUT;
149109998Smarkm#ifndef OPENSSL_NO_DES
150280304Sjkim        else if (!strcmp(*args, "-des3"))
151280304Sjkim            cipher = EVP_des_ede3_cbc();
152280304Sjkim        else if (!strcmp(*args, "-des"))
153280304Sjkim            cipher = EVP_des_cbc();
15459191Skris#endif
155194206Ssimon#ifndef OPENSSL_NO_SEED
156280304Sjkim        else if (!strcmp(*args, "-seed"))
157280304Sjkim            cipher = EVP_seed_cbc();
158194206Ssimon#endif
159109998Smarkm#ifndef OPENSSL_NO_RC2
160280304Sjkim        else if (!strcmp(*args, "-rc2-40"))
161280304Sjkim            cipher = EVP_rc2_40_cbc();
162280304Sjkim        else if (!strcmp(*args, "-rc2-128"))
163280304Sjkim            cipher = EVP_rc2_cbc();
164280304Sjkim        else if (!strcmp(*args, "-rc2-64"))
165280304Sjkim            cipher = EVP_rc2_64_cbc();
16659191Skris#endif
167109998Smarkm#ifndef OPENSSL_NO_AES
168280304Sjkim        else if (!strcmp(*args, "-aes128"))
169280304Sjkim            cipher = EVP_aes_128_cbc();
170280304Sjkim        else if (!strcmp(*args, "-aes192"))
171280304Sjkim            cipher = EVP_aes_192_cbc();
172280304Sjkim        else if (!strcmp(*args, "-aes256"))
173280304Sjkim            cipher = EVP_aes_256_cbc();
174109998Smarkm#endif
175162911Ssimon#ifndef OPENSSL_NO_CAMELLIA
176280304Sjkim        else if (!strcmp(*args, "-camellia128"))
177280304Sjkim            cipher = EVP_camellia_128_cbc();
178280304Sjkim        else if (!strcmp(*args, "-camellia192"))
179280304Sjkim            cipher = EVP_camellia_192_cbc();
180280304Sjkim        else if (!strcmp(*args, "-camellia256"))
181280304Sjkim            cipher = EVP_camellia_256_cbc();
182162911Ssimon#endif
183280304Sjkim        else if (!strcmp(*args, "-text"))
184280304Sjkim            flags |= PKCS7_TEXT;
185280304Sjkim        else if (!strcmp(*args, "-nointern"))
186280304Sjkim            flags |= PKCS7_NOINTERN;
187280304Sjkim        else if (!strcmp(*args, "-noverify"))
188280304Sjkim            flags |= PKCS7_NOVERIFY;
189280304Sjkim        else if (!strcmp(*args, "-nochain"))
190280304Sjkim            flags |= PKCS7_NOCHAIN;
191280304Sjkim        else if (!strcmp(*args, "-nocerts"))
192280304Sjkim            flags |= PKCS7_NOCERTS;
193280304Sjkim        else if (!strcmp(*args, "-noattr"))
194280304Sjkim            flags |= PKCS7_NOATTR;
195280304Sjkim        else if (!strcmp(*args, "-nodetach"))
196280304Sjkim            flags &= ~PKCS7_DETACHED;
197280304Sjkim        else if (!strcmp(*args, "-nosmimecap"))
198280304Sjkim            flags |= PKCS7_NOSMIMECAP;
199280304Sjkim        else if (!strcmp(*args, "-binary"))
200280304Sjkim            flags |= PKCS7_BINARY;
201280304Sjkim        else if (!strcmp(*args, "-nosigs"))
202280304Sjkim            flags |= PKCS7_NOSIGS;
203280304Sjkim        else if (!strcmp(*args, "-stream"))
204280304Sjkim            indef = 1;
205280304Sjkim        else if (!strcmp(*args, "-indef"))
206280304Sjkim            indef = 1;
207280304Sjkim        else if (!strcmp(*args, "-noindef"))
208280304Sjkim            indef = 0;
209280304Sjkim        else if (!strcmp(*args, "-nooldmime"))
210280304Sjkim            flags |= PKCS7_NOOLDMIMETYPE;
211280304Sjkim        else if (!strcmp(*args, "-crlfeol"))
212280304Sjkim            flags |= PKCS7_CRLFEOL;
213280304Sjkim        else if (!strcmp(*args, "-rand")) {
214280304Sjkim            if (!args[1])
215280304Sjkim                goto argerr;
216280304Sjkim            args++;
217280304Sjkim            inrand = *args;
218280304Sjkim            need_rand = 1;
219280304Sjkim        }
220111147Snectar#ifndef OPENSSL_NO_ENGINE
221280304Sjkim        else if (!strcmp(*args, "-engine")) {
222280304Sjkim            if (!args[1])
223280304Sjkim                goto argerr;
224280304Sjkim            engine = *++args;
225280304Sjkim        }
226111147Snectar#endif
227280304Sjkim        else if (!strcmp(*args, "-passin")) {
228280304Sjkim            if (!args[1])
229280304Sjkim                goto argerr;
230280304Sjkim            passargin = *++args;
231280304Sjkim        } else if (!strcmp(*args, "-to")) {
232280304Sjkim            if (!args[1])
233280304Sjkim                goto argerr;
234280304Sjkim            to = *++args;
235280304Sjkim        } else if (!strcmp(*args, "-from")) {
236280304Sjkim            if (!args[1])
237280304Sjkim                goto argerr;
238280304Sjkim            from = *++args;
239280304Sjkim        } else if (!strcmp(*args, "-subject")) {
240280304Sjkim            if (!args[1])
241280304Sjkim                goto argerr;
242280304Sjkim            subject = *++args;
243280304Sjkim        } else if (!strcmp(*args, "-signer")) {
244280304Sjkim            if (!args[1])
245280304Sjkim                goto argerr;
246280304Sjkim            /* If previous -signer argument add signer to list */
247238405Sjkim
248280304Sjkim            if (signerfile) {
249280304Sjkim                if (!sksigners)
250280304Sjkim                    sksigners = sk_OPENSSL_STRING_new_null();
251280304Sjkim                sk_OPENSSL_STRING_push(sksigners, signerfile);
252280304Sjkim                if (!keyfile)
253280304Sjkim                    keyfile = signerfile;
254280304Sjkim                if (!skkeys)
255280304Sjkim                    skkeys = sk_OPENSSL_STRING_new_null();
256280304Sjkim                sk_OPENSSL_STRING_push(skkeys, keyfile);
257280304Sjkim                keyfile = NULL;
258280304Sjkim            }
259280304Sjkim            signerfile = *++args;
260280304Sjkim        } else if (!strcmp(*args, "-recip")) {
261280304Sjkim            if (!args[1])
262280304Sjkim                goto argerr;
263280304Sjkim            recipfile = *++args;
264280304Sjkim        } else if (!strcmp(*args, "-md")) {
265280304Sjkim            if (!args[1])
266280304Sjkim                goto argerr;
267280304Sjkim            sign_md = EVP_get_digestbyname(*++args);
268280304Sjkim            if (sign_md == NULL) {
269280304Sjkim                BIO_printf(bio_err, "Unknown digest %s\n", *args);
270280304Sjkim                goto argerr;
271280304Sjkim            }
272280304Sjkim        } else if (!strcmp(*args, "-inkey")) {
273280304Sjkim            if (!args[1])
274280304Sjkim                goto argerr;
275280304Sjkim            /* If previous -inkey arument add signer to list */
276280304Sjkim            if (keyfile) {
277280304Sjkim                if (!signerfile) {
278280304Sjkim                    BIO_puts(bio_err, "Illegal -inkey without -signer\n");
279280304Sjkim                    goto argerr;
280280304Sjkim                }
281280304Sjkim                if (!sksigners)
282280304Sjkim                    sksigners = sk_OPENSSL_STRING_new_null();
283280304Sjkim                sk_OPENSSL_STRING_push(sksigners, signerfile);
284280304Sjkim                signerfile = NULL;
285280304Sjkim                if (!skkeys)
286280304Sjkim                    skkeys = sk_OPENSSL_STRING_new_null();
287280304Sjkim                sk_OPENSSL_STRING_push(skkeys, keyfile);
288280304Sjkim            }
289280304Sjkim            keyfile = *++args;
290280304Sjkim        } else if (!strcmp(*args, "-keyform")) {
291280304Sjkim            if (!args[1])
292280304Sjkim                goto argerr;
293280304Sjkim            keyform = str2fmt(*++args);
294280304Sjkim        } else if (!strcmp(*args, "-certfile")) {
295280304Sjkim            if (!args[1])
296280304Sjkim                goto argerr;
297280304Sjkim            certfile = *++args;
298280304Sjkim        } else if (!strcmp(*args, "-CAfile")) {
299280304Sjkim            if (!args[1])
300280304Sjkim                goto argerr;
301280304Sjkim            CAfile = *++args;
302280304Sjkim        } else if (!strcmp(*args, "-CApath")) {
303280304Sjkim            if (!args[1])
304280304Sjkim                goto argerr;
305280304Sjkim            CApath = *++args;
306280304Sjkim        } else if (!strcmp(*args, "-in")) {
307280304Sjkim            if (!args[1])
308280304Sjkim                goto argerr;
309280304Sjkim            infile = *++args;
310280304Sjkim        } else if (!strcmp(*args, "-inform")) {
311280304Sjkim            if (!args[1])
312280304Sjkim                goto argerr;
313280304Sjkim            informat = str2fmt(*++args);
314280304Sjkim        } else if (!strcmp(*args, "-outform")) {
315280304Sjkim            if (!args[1])
316280304Sjkim                goto argerr;
317280304Sjkim            outformat = str2fmt(*++args);
318280304Sjkim        } else if (!strcmp(*args, "-out")) {
319280304Sjkim            if (!args[1])
320280304Sjkim                goto argerr;
321280304Sjkim            outfile = *++args;
322280304Sjkim        } else if (!strcmp(*args, "-content")) {
323280304Sjkim            if (!args[1])
324280304Sjkim                goto argerr;
325280304Sjkim            contfile = *++args;
326280304Sjkim        } else if (args_verify(&args, NULL, &badarg, bio_err, &vpm))
327280304Sjkim            continue;
328280304Sjkim        else if ((cipher = EVP_get_cipherbyname(*args + 1)) == NULL)
329280304Sjkim            badarg = 1;
330280304Sjkim        args++;
331280304Sjkim    }
33259191Skris
333280304Sjkim    if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) {
334280304Sjkim        BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
335280304Sjkim        goto argerr;
336280304Sjkim    }
337160814Ssimon
338280304Sjkim    if (operation & SMIME_SIGNERS) {
339280304Sjkim        /* Check to see if any final signer needs to be appended */
340280304Sjkim        if (keyfile && !signerfile) {
341280304Sjkim            BIO_puts(bio_err, "Illegal -inkey without -signer\n");
342280304Sjkim            goto argerr;
343280304Sjkim        }
344280304Sjkim        if (signerfile) {
345280304Sjkim            if (!sksigners)
346280304Sjkim                sksigners = sk_OPENSSL_STRING_new_null();
347280304Sjkim            sk_OPENSSL_STRING_push(sksigners, signerfile);
348280304Sjkim            if (!skkeys)
349280304Sjkim                skkeys = sk_OPENSSL_STRING_new_null();
350280304Sjkim            if (!keyfile)
351280304Sjkim                keyfile = signerfile;
352280304Sjkim            sk_OPENSSL_STRING_push(skkeys, keyfile);
353280304Sjkim        }
354280304Sjkim        if (!sksigners) {
355280304Sjkim            BIO_printf(bio_err, "No signer certificate specified\n");
356280304Sjkim            badarg = 1;
357280304Sjkim        }
358280304Sjkim        signerfile = NULL;
359280304Sjkim        keyfile = NULL;
360280304Sjkim        need_rand = 1;
361280304Sjkim    } else if (operation == SMIME_DECRYPT) {
362280304Sjkim        if (!recipfile && !keyfile) {
363280304Sjkim            BIO_printf(bio_err,
364280304Sjkim                       "No recipient certificate or key specified\n");
365280304Sjkim            badarg = 1;
366280304Sjkim        }
367280304Sjkim    } else if (operation == SMIME_ENCRYPT) {
368280304Sjkim        if (!*args) {
369280304Sjkim            BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
370280304Sjkim            badarg = 1;
371280304Sjkim        }
372280304Sjkim        need_rand = 1;
373280304Sjkim    } else if (!operation)
374280304Sjkim        badarg = 1;
37559191Skris
376280304Sjkim    if (badarg) {
377280304Sjkim argerr:
378280304Sjkim        BIO_printf(bio_err, "Usage smime [options] cert.pem ...\n");
379280304Sjkim        BIO_printf(bio_err, "where options are\n");
380280304Sjkim        BIO_printf(bio_err, "-encrypt       encrypt message\n");
381280304Sjkim        BIO_printf(bio_err, "-decrypt       decrypt encrypted message\n");
382280304Sjkim        BIO_printf(bio_err, "-sign          sign message\n");
383280304Sjkim        BIO_printf(bio_err, "-verify        verify signed message\n");
384280304Sjkim        BIO_printf(bio_err, "-pk7out        output PKCS#7 structure\n");
385109998Smarkm#ifndef OPENSSL_NO_DES
386280304Sjkim        BIO_printf(bio_err, "-des3          encrypt with triple DES\n");
387280304Sjkim        BIO_printf(bio_err, "-des           encrypt with DES\n");
38859191Skris#endif
389194206Ssimon#ifndef OPENSSL_NO_SEED
390280304Sjkim        BIO_printf(bio_err, "-seed          encrypt with SEED\n");
391194206Ssimon#endif
392109998Smarkm#ifndef OPENSSL_NO_RC2
393280304Sjkim        BIO_printf(bio_err, "-rc2-40        encrypt with RC2-40 (default)\n");
394280304Sjkim        BIO_printf(bio_err, "-rc2-64        encrypt with RC2-64\n");
395280304Sjkim        BIO_printf(bio_err, "-rc2-128       encrypt with RC2-128\n");
39659191Skris#endif
397109998Smarkm#ifndef OPENSSL_NO_AES
398280304Sjkim        BIO_printf(bio_err, "-aes128, -aes192, -aes256\n");
399280304Sjkim        BIO_printf(bio_err,
400280304Sjkim                   "               encrypt PEM output with cbc aes\n");
401109998Smarkm#endif
402162911Ssimon#ifndef OPENSSL_NO_CAMELLIA
403280304Sjkim        BIO_printf(bio_err, "-camellia128, -camellia192, -camellia256\n");
404280304Sjkim        BIO_printf(bio_err,
405280304Sjkim                   "               encrypt PEM output with cbc camellia\n");
406162911Ssimon#endif
407280304Sjkim        BIO_printf(bio_err,
408280304Sjkim                   "-nointern      don't search certificates in message for signer\n");
409280304Sjkim        BIO_printf(bio_err,
410280304Sjkim                   "-nosigs        don't verify message signature\n");
411280304Sjkim        BIO_printf(bio_err,
412280304Sjkim                   "-noverify      don't verify signers certificate\n");
413280304Sjkim        BIO_printf(bio_err,
414280304Sjkim                   "-nocerts       don't include signers certificate when signing\n");
415280304Sjkim        BIO_printf(bio_err, "-nodetach      use opaque signing\n");
416280304Sjkim        BIO_printf(bio_err,
417280304Sjkim                   "-noattr        don't include any signed attributes\n");
418280304Sjkim        BIO_printf(bio_err,
419280304Sjkim                   "-binary        don't translate message to text\n");
420280304Sjkim        BIO_printf(bio_err, "-certfile file other certificates file\n");
421280304Sjkim        BIO_printf(bio_err, "-signer file   signer certificate file\n");
422280304Sjkim        BIO_printf(bio_err,
423280304Sjkim                   "-recip  file   recipient certificate file for decryption\n");
424280304Sjkim        BIO_printf(bio_err, "-in file       input file\n");
425280304Sjkim        BIO_printf(bio_err,
426280304Sjkim                   "-inform arg    input format SMIME (default), PEM or DER\n");
427280304Sjkim        BIO_printf(bio_err,
428280304Sjkim                   "-inkey file    input private key (if not signer or recipient)\n");
429280304Sjkim        BIO_printf(bio_err,
430280304Sjkim                   "-keyform arg   input private key format (PEM or ENGINE)\n");
431280304Sjkim        BIO_printf(bio_err, "-out file      output file\n");
432280304Sjkim        BIO_printf(bio_err,
433280304Sjkim                   "-outform arg   output format SMIME (default), PEM or DER\n");
434280304Sjkim        BIO_printf(bio_err,
435280304Sjkim                   "-content file  supply or override content for detached signature\n");
436280304Sjkim        BIO_printf(bio_err, "-to addr       to address\n");
437280304Sjkim        BIO_printf(bio_err, "-from ad       from address\n");
438280304Sjkim        BIO_printf(bio_err, "-subject s     subject\n");
439280304Sjkim        BIO_printf(bio_err,
440280304Sjkim                   "-text          include or delete text MIME headers\n");
441280304Sjkim        BIO_printf(bio_err,
442280304Sjkim                   "-CApath dir    trusted certificates directory\n");
443280304Sjkim        BIO_printf(bio_err, "-CAfile file   trusted certificates file\n");
444280304Sjkim        BIO_printf(bio_err,
445284285Sjkim                   "-no_alt_chains only ever use the first certificate chain found\n");
446284285Sjkim        BIO_printf(bio_err,
447280304Sjkim                   "-crl_check     check revocation status of signer's certificate using CRLs\n");
448280304Sjkim        BIO_printf(bio_err,
449280304Sjkim                   "-crl_check_all check revocation status of signer's certificate chain using CRLs\n");
450111147Snectar#ifndef OPENSSL_NO_ENGINE
451280304Sjkim        BIO_printf(bio_err,
452280304Sjkim                   "-engine e      use engine e, possibly a hardware device.\n");
453111147Snectar#endif
454280304Sjkim        BIO_printf(bio_err, "-passin arg    input file pass phrase source\n");
455280304Sjkim        BIO_printf(bio_err, "-rand file%cfile%c...\n", LIST_SEPARATOR_CHAR,
456280304Sjkim                   LIST_SEPARATOR_CHAR);
457280304Sjkim        BIO_printf(bio_err,
458280304Sjkim                   "               load the file (or the files in the directory) into\n");
459280304Sjkim        BIO_printf(bio_err, "               the random number generator\n");
460280304Sjkim        BIO_printf(bio_err,
461280304Sjkim                   "cert.pem       recipient certificate(s) for encryption\n");
462280304Sjkim        goto end;
463280304Sjkim    }
464111147Snectar#ifndef OPENSSL_NO_ENGINE
465280304Sjkim    e = setup_engine(bio_err, engine, 0);
466111147Snectar#endif
467109998Smarkm
468280304Sjkim    if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
469280304Sjkim        BIO_printf(bio_err, "Error getting password\n");
470280304Sjkim        goto end;
471280304Sjkim    }
47259191Skris
473280304Sjkim    if (need_rand) {
474280304Sjkim        app_RAND_load_file(NULL, bio_err, (inrand != NULL));
475280304Sjkim        if (inrand != NULL)
476280304Sjkim            BIO_printf(bio_err, "%ld semi-random bytes loaded\n",
477280304Sjkim                       app_RAND_load_files(inrand));
478280304Sjkim    }
47959191Skris
480280304Sjkim    ret = 2;
48159191Skris
482280304Sjkim    if (!(operation & SMIME_SIGNERS))
483280304Sjkim        flags &= ~PKCS7_DETACHED;
48459191Skris
485280304Sjkim    if (operation & SMIME_OP) {
486280304Sjkim        if (outformat == FORMAT_ASN1)
487280304Sjkim            outmode = "wb";
488280304Sjkim    } else {
489280304Sjkim        if (flags & PKCS7_BINARY)
490280304Sjkim            outmode = "wb";
491280304Sjkim    }
492238405Sjkim
493280304Sjkim    if (operation & SMIME_IP) {
494280304Sjkim        if (informat == FORMAT_ASN1)
495280304Sjkim            inmode = "rb";
496280304Sjkim    } else {
497280304Sjkim        if (flags & PKCS7_BINARY)
498280304Sjkim            inmode = "rb";
499280304Sjkim    }
50059191Skris
501280304Sjkim    if (operation == SMIME_ENCRYPT) {
502280304Sjkim        if (!cipher) {
503280304Sjkim#ifndef OPENSSL_NO_DES
504280304Sjkim            cipher = EVP_des_ede3_cbc();
50559191Skris#else
506280304Sjkim            BIO_printf(bio_err, "No cipher selected\n");
507280304Sjkim            goto end;
50859191Skris#endif
509280304Sjkim        }
510280304Sjkim        encerts = sk_X509_new_null();
511280304Sjkim        while (*args) {
512280304Sjkim            if (!(cert = load_cert(bio_err, *args, FORMAT_PEM,
513280304Sjkim                                   NULL, e, "recipient certificate file"))) {
514280304Sjkim#if 0                           /* An appropriate message is already printed */
515280304Sjkim                BIO_printf(bio_err,
516280304Sjkim                           "Can't read recipient certificate file %s\n",
517280304Sjkim                           *args);
518109998Smarkm#endif
519280304Sjkim                goto end;
520280304Sjkim            }
521280304Sjkim            sk_X509_push(encerts, cert);
522280304Sjkim            cert = NULL;
523280304Sjkim            args++;
524280304Sjkim        }
525280304Sjkim    }
52659191Skris
527280304Sjkim    if (certfile) {
528280304Sjkim        if (!(other = load_certs(bio_err, certfile, FORMAT_PEM, NULL,
529280304Sjkim                                 e, "certificate file"))) {
530280304Sjkim            ERR_print_errors(bio_err);
531280304Sjkim            goto end;
532280304Sjkim        }
533280304Sjkim    }
53459191Skris
535280304Sjkim    if (recipfile && (operation == SMIME_DECRYPT)) {
536280304Sjkim        if (!(recip = load_cert(bio_err, recipfile, FORMAT_PEM, NULL,
537280304Sjkim                                e, "recipient certificate file"))) {
538280304Sjkim            ERR_print_errors(bio_err);
539280304Sjkim            goto end;
540280304Sjkim        }
541280304Sjkim    }
54259191Skris
543280304Sjkim    if (operation == SMIME_DECRYPT) {
544280304Sjkim        if (!keyfile)
545280304Sjkim            keyfile = recipfile;
546280304Sjkim    } else if (operation == SMIME_SIGN) {
547280304Sjkim        if (!keyfile)
548280304Sjkim            keyfile = signerfile;
549280304Sjkim    } else
550280304Sjkim        keyfile = NULL;
55159191Skris
552280304Sjkim    if (keyfile) {
553280304Sjkim        key = load_key(bio_err, keyfile, keyform, 0, passin, e,
554280304Sjkim                       "signing key file");
555280304Sjkim        if (!key)
556280304Sjkim            goto end;
557280304Sjkim    }
55859191Skris
559280304Sjkim    if (infile) {
560280304Sjkim        if (!(in = BIO_new_file(infile, inmode))) {
561280304Sjkim            BIO_printf(bio_err, "Can't open input file %s\n", infile);
562280304Sjkim            goto end;
563280304Sjkim        }
564280304Sjkim    } else
565280304Sjkim        in = BIO_new_fp(stdin, BIO_NOCLOSE);
56659191Skris
567280304Sjkim    if (operation & SMIME_IP) {
568280304Sjkim        if (informat == FORMAT_SMIME)
569280304Sjkim            p7 = SMIME_read_PKCS7(in, &indata);
570280304Sjkim        else if (informat == FORMAT_PEM)
571280304Sjkim            p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
572280304Sjkim        else if (informat == FORMAT_ASN1)
573280304Sjkim            p7 = d2i_PKCS7_bio(in, NULL);
574280304Sjkim        else {
575280304Sjkim            BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
576280304Sjkim            goto end;
577280304Sjkim        }
578238405Sjkim
579280304Sjkim        if (!p7) {
580280304Sjkim            BIO_printf(bio_err, "Error reading S/MIME message\n");
581280304Sjkim            goto end;
582280304Sjkim        }
583280304Sjkim        if (contfile) {
584280304Sjkim            BIO_free(indata);
585280304Sjkim            if (!(indata = BIO_new_file(contfile, "rb"))) {
586280304Sjkim                BIO_printf(bio_err, "Can't read content file %s\n", contfile);
587280304Sjkim                goto end;
588280304Sjkim            }
589280304Sjkim        }
590280304Sjkim    }
591238405Sjkim
592280304Sjkim    if (outfile) {
593280304Sjkim        if (!(out = BIO_new_file(outfile, outmode))) {
594280304Sjkim            BIO_printf(bio_err, "Can't open output file %s\n", outfile);
595280304Sjkim            goto end;
596280304Sjkim        }
597280304Sjkim    } else {
598280304Sjkim        out = BIO_new_fp(stdout, BIO_NOCLOSE);
599109998Smarkm#ifdef OPENSSL_SYS_VMS
600280304Sjkim        {
601280304Sjkim            BIO *tmpbio = BIO_new(BIO_f_linebuffer());
602280304Sjkim            out = BIO_push(tmpbio, out);
603280304Sjkim        }
60468651Skris#endif
605280304Sjkim    }
60659191Skris
607280304Sjkim    if (operation == SMIME_VERIFY) {
608280304Sjkim        if (!(store = setup_verify(bio_err, CAfile, CApath)))
609280304Sjkim            goto end;
610280304Sjkim        X509_STORE_set_verify_cb(store, smime_cb);
611280304Sjkim        if (vpm)
612280304Sjkim            X509_STORE_set1_param(store, vpm);
613280304Sjkim    }
61459191Skris
615280304Sjkim    ret = 3;
616109998Smarkm
617280304Sjkim    if (operation == SMIME_ENCRYPT) {
618280304Sjkim        if (indef)
619280304Sjkim            flags |= PKCS7_STREAM;
620280304Sjkim        p7 = PKCS7_encrypt(encerts, in, cipher, flags);
621280304Sjkim    } else if (operation & SMIME_SIGNERS) {
622280304Sjkim        int i;
623280304Sjkim        /*
624280304Sjkim         * If detached data content we only enable streaming if S/MIME output
625280304Sjkim         * format.
626280304Sjkim         */
627280304Sjkim        if (operation == SMIME_SIGN) {
628280304Sjkim            if (flags & PKCS7_DETACHED) {
629280304Sjkim                if (outformat == FORMAT_SMIME)
630280304Sjkim                    flags |= PKCS7_STREAM;
631280304Sjkim            } else if (indef)
632280304Sjkim                flags |= PKCS7_STREAM;
633280304Sjkim            flags |= PKCS7_PARTIAL;
634280304Sjkim            p7 = PKCS7_sign(NULL, NULL, other, in, flags);
635280304Sjkim            if (!p7)
636280304Sjkim                goto end;
637280304Sjkim        } else
638280304Sjkim            flags |= PKCS7_REUSE_DIGEST;
639280304Sjkim        for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) {
640280304Sjkim            signerfile = sk_OPENSSL_STRING_value(sksigners, i);
641280304Sjkim            keyfile = sk_OPENSSL_STRING_value(skkeys, i);
642280304Sjkim            signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL,
643280304Sjkim                               e, "signer certificate");
644280304Sjkim            if (!signer)
645280304Sjkim                goto end;
646280304Sjkim            key = load_key(bio_err, keyfile, keyform, 0, passin, e,
647280304Sjkim                           "signing key file");
648280304Sjkim            if (!key)
649280304Sjkim                goto end;
650280304Sjkim            if (!PKCS7_sign_add_signer(p7, signer, key, sign_md, flags))
651280304Sjkim                goto end;
652280304Sjkim            X509_free(signer);
653280304Sjkim            signer = NULL;
654280304Sjkim            EVP_PKEY_free(key);
655280304Sjkim            key = NULL;
656280304Sjkim        }
657280304Sjkim        /* If not streaming or resigning finalize structure */
658280304Sjkim        if ((operation == SMIME_SIGN) && !(flags & PKCS7_STREAM)) {
659280304Sjkim            if (!PKCS7_final(p7, in, flags))
660280304Sjkim                goto end;
661280304Sjkim        }
662280304Sjkim    }
66359191Skris
664280304Sjkim    if (!p7) {
665280304Sjkim        BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
666280304Sjkim        goto end;
667280304Sjkim    }
66859191Skris
669280304Sjkim    ret = 4;
670280304Sjkim    if (operation == SMIME_DECRYPT) {
671280304Sjkim        if (!PKCS7_decrypt(p7, key, recip, out, flags)) {
672280304Sjkim            BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n");
673280304Sjkim            goto end;
674280304Sjkim        }
675280304Sjkim    } else if (operation == SMIME_VERIFY) {
676280304Sjkim        STACK_OF(X509) *signers;
677280304Sjkim        if (PKCS7_verify(p7, other, store, indata, out, flags))
678280304Sjkim            BIO_printf(bio_err, "Verification successful\n");
679280304Sjkim        else {
680280304Sjkim            BIO_printf(bio_err, "Verification failure\n");
681280304Sjkim            goto end;
682280304Sjkim        }
683280304Sjkim        signers = PKCS7_get0_signers(p7, other, flags);
684280304Sjkim        if (!save_certs(signerfile, signers)) {
685280304Sjkim            BIO_printf(bio_err, "Error writing signers to %s\n", signerfile);
686280304Sjkim            ret = 5;
687280304Sjkim            goto end;
688280304Sjkim        }
689280304Sjkim        sk_X509_free(signers);
690280304Sjkim    } else if (operation == SMIME_PK7OUT)
691280304Sjkim        PEM_write_bio_PKCS7(out, p7);
692280304Sjkim    else {
693280304Sjkim        if (to)
694280304Sjkim            BIO_printf(out, "To: %s\n", to);
695280304Sjkim        if (from)
696280304Sjkim            BIO_printf(out, "From: %s\n", from);
697280304Sjkim        if (subject)
698280304Sjkim            BIO_printf(out, "Subject: %s\n", subject);
699280304Sjkim        if (outformat == FORMAT_SMIME) {
700280304Sjkim            if (operation == SMIME_RESIGN)
701280304Sjkim                SMIME_write_PKCS7(out, p7, indata, flags);
702280304Sjkim            else
703280304Sjkim                SMIME_write_PKCS7(out, p7, in, flags);
704280304Sjkim        } else if (outformat == FORMAT_PEM)
705280304Sjkim            PEM_write_bio_PKCS7_stream(out, p7, in, flags);
706280304Sjkim        else if (outformat == FORMAT_ASN1)
707280304Sjkim            i2d_PKCS7_bio_stream(out, p7, in, flags);
708280304Sjkim        else {
709280304Sjkim            BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
710280304Sjkim            goto end;
711280304Sjkim        }
712280304Sjkim    }
713280304Sjkim    ret = 0;
714280304Sjkim end:
715280304Sjkim    if (need_rand)
716280304Sjkim        app_RAND_write_file(NULL, bio_err);
717280304Sjkim    if (ret)
718280304Sjkim        ERR_print_errors(bio_err);
719280304Sjkim    sk_X509_pop_free(encerts, X509_free);
720280304Sjkim    sk_X509_pop_free(other, X509_free);
721280304Sjkim    if (vpm)
722280304Sjkim        X509_VERIFY_PARAM_free(vpm);
723280304Sjkim    if (sksigners)
724280304Sjkim        sk_OPENSSL_STRING_free(sksigners);
725280304Sjkim    if (skkeys)
726280304Sjkim        sk_OPENSSL_STRING_free(skkeys);
727280304Sjkim    X509_STORE_free(store);
728280304Sjkim    X509_free(cert);
729280304Sjkim    X509_free(recip);
730280304Sjkim    X509_free(signer);
731280304Sjkim    EVP_PKEY_free(key);
732280304Sjkim    PKCS7_free(p7);
733280304Sjkim    BIO_free(in);
734280304Sjkim    BIO_free(indata);
735280304Sjkim    BIO_free_all(out);
736280304Sjkim    if (passin)
737280304Sjkim        OPENSSL_free(passin);
738280304Sjkim    return (ret);
73959191Skris}
74059191Skris
74159191Skrisstatic int save_certs(char *signerfile, STACK_OF(X509) *signers)
742280304Sjkim{
743280304Sjkim    int i;
744280304Sjkim    BIO *tmp;
745280304Sjkim    if (!signerfile)
746280304Sjkim        return 1;
747280304Sjkim    tmp = BIO_new_file(signerfile, "w");
748280304Sjkim    if (!tmp)
749280304Sjkim        return 0;
750280304Sjkim    for (i = 0; i < sk_X509_num(signers); i++)
751280304Sjkim        PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
752280304Sjkim    BIO_free(tmp);
753280304Sjkim    return 1;
754280304Sjkim}
755160814Ssimon
756160814Ssimon/* Minimal callback just to output policy info (if any) */
757160814Ssimon
758160814Ssimonstatic int smime_cb(int ok, X509_STORE_CTX *ctx)
759280304Sjkim{
760280304Sjkim    int error;
761160814Ssimon
762280304Sjkim    error = X509_STORE_CTX_get_error(ctx);
763160814Ssimon
764280304Sjkim    if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
765280304Sjkim        && ((error != X509_V_OK) || (ok != 2)))
766280304Sjkim        return ok;
767160814Ssimon
768280304Sjkim    policies_print(NULL, ctx);
769160814Ssimon
770280304Sjkim    return ok;
771160814Ssimon
772280304Sjkim}
773