1183234Ssimon/* apps/cms.c */
2280304Sjkim/*
3280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4183234Ssimon * project.
5183234Ssimon */
6183234Ssimon/* ====================================================================
7183234Ssimon * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
8183234Ssimon *
9183234Ssimon * Redistribution and use in source and binary forms, with or without
10183234Ssimon * modification, are permitted provided that the following conditions
11183234Ssimon * are met:
12183234Ssimon *
13183234Ssimon * 1. Redistributions of source code must retain the above copyright
14280304Sjkim *    notice, this list of conditions and the following disclaimer.
15183234Ssimon *
16183234Ssimon * 2. Redistributions in binary form must reproduce the above copyright
17183234Ssimon *    notice, this list of conditions and the following disclaimer in
18183234Ssimon *    the documentation and/or other materials provided with the
19183234Ssimon *    distribution.
20183234Ssimon *
21183234Ssimon * 3. All advertising materials mentioning features or use of this
22183234Ssimon *    software must display the following acknowledgment:
23183234Ssimon *    "This product includes software developed by the OpenSSL Project
24183234Ssimon *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25183234Ssimon *
26183234Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27183234Ssimon *    endorse or promote products derived from this software without
28183234Ssimon *    prior written permission. For written permission, please contact
29183234Ssimon *    licensing@OpenSSL.org.
30183234Ssimon *
31183234Ssimon * 5. Products derived from this software may not be called "OpenSSL"
32183234Ssimon *    nor may "OpenSSL" appear in their names without prior written
33183234Ssimon *    permission of the OpenSSL Project.
34183234Ssimon *
35183234Ssimon * 6. Redistributions of any form whatsoever must retain the following
36183234Ssimon *    acknowledgment:
37183234Ssimon *    "This product includes software developed by the OpenSSL Project
38183234Ssimon *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39183234Ssimon *
40183234Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41183234Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42183234Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43183234Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44183234Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45183234Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46183234Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47183234Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48183234Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49183234Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50183234Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51183234Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
52183234Ssimon * ====================================================================
53183234Ssimon */
54183234Ssimon
55183234Ssimon/* CMS utility function */
56183234Ssimon
57183234Ssimon#include <stdio.h>
58183234Ssimon#include <string.h>
59183234Ssimon#include "apps.h"
60183234Ssimon
61183234Ssimon#ifndef OPENSSL_NO_CMS
62183234Ssimon
63280304Sjkim# include <openssl/crypto.h>
64280304Sjkim# include <openssl/pem.h>
65280304Sjkim# include <openssl/err.h>
66280304Sjkim# include <openssl/x509_vfy.h>
67280304Sjkim# include <openssl/x509v3.h>
68280304Sjkim# include <openssl/cms.h>
69183234Ssimon
70280304Sjkim# undef PROG
71280304Sjkim# define PROG cms_main
72183234Ssimonstatic int save_certs(char *signerfile, STACK_OF(X509) *signers);
73183234Ssimonstatic int cms_cb(int ok, X509_STORE_CTX *ctx);
74183234Ssimonstatic void receipt_request_print(BIO *out, CMS_ContentInfo *cms);
75280304Sjkimstatic CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING)
76280304Sjkim                                                *rr_to, int rr_allorfirst, STACK_OF(OPENSSL_STRING)
77280304Sjkim                                                *rr_from);
78183234Ssimon
79280304Sjkim# define SMIME_OP        0x10
80280304Sjkim# define SMIME_IP        0x20
81280304Sjkim# define SMIME_SIGNERS   0x40
82280304Sjkim# define SMIME_ENCRYPT           (1 | SMIME_OP)
83280304Sjkim# define SMIME_DECRYPT           (2 | SMIME_IP)
84280304Sjkim# define SMIME_SIGN              (3 | SMIME_OP | SMIME_SIGNERS)
85280304Sjkim# define SMIME_VERIFY            (4 | SMIME_IP)
86280304Sjkim# define SMIME_CMSOUT            (5 | SMIME_IP | SMIME_OP)
87280304Sjkim# define SMIME_RESIGN            (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
88280304Sjkim# define SMIME_DATAOUT           (7 | SMIME_IP)
89280304Sjkim# define SMIME_DATA_CREATE       (8 | SMIME_OP)
90280304Sjkim# define SMIME_DIGEST_VERIFY     (9 | SMIME_IP)
91280304Sjkim# define SMIME_DIGEST_CREATE     (10 | SMIME_OP)
92280304Sjkim# define SMIME_UNCOMPRESS        (11 | SMIME_IP)
93280304Sjkim# define SMIME_COMPRESS          (12 | SMIME_OP)
94280304Sjkim# define SMIME_ENCRYPTED_DECRYPT (13 | SMIME_IP)
95280304Sjkim# define SMIME_ENCRYPTED_ENCRYPT (14 | SMIME_OP)
96280304Sjkim# define SMIME_SIGN_RECEIPT      (15 | SMIME_IP | SMIME_OP)
97280304Sjkim# define SMIME_VERIFY_RECEIPT    (16 | SMIME_IP)
98183234Ssimon
99238405Sjkimint verify_err = 0;
100238405Sjkim
101183234Ssimonint MAIN(int, char **);
102183234Ssimon
103183234Ssimonint MAIN(int argc, char **argv)
104280304Sjkim{
105280304Sjkim    ENGINE *e = NULL;
106280304Sjkim    int operation = 0;
107280304Sjkim    int ret = 0;
108280304Sjkim    char **args;
109280304Sjkim    const char *inmode = "r", *outmode = "w";
110280304Sjkim    char *infile = NULL, *outfile = NULL, *rctfile = NULL;
111280304Sjkim    char *signerfile = NULL, *recipfile = NULL;
112280304Sjkim    STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL;
113280304Sjkim    char *certfile = NULL, *keyfile = NULL, *contfile = NULL;
114280304Sjkim    char *certsoutfile = NULL;
115280304Sjkim    const EVP_CIPHER *cipher = NULL;
116280304Sjkim    CMS_ContentInfo *cms = NULL, *rcms = NULL;
117280304Sjkim    X509_STORE *store = NULL;
118280304Sjkim    X509 *cert = NULL, *recip = NULL, *signer = NULL;
119280304Sjkim    EVP_PKEY *key = NULL;
120280304Sjkim    STACK_OF(X509) *encerts = NULL, *other = NULL;
121280304Sjkim    BIO *in = NULL, *out = NULL, *indata = NULL, *rctin = NULL;
122280304Sjkim    int badarg = 0;
123280304Sjkim    int flags = CMS_DETACHED, noout = 0, print = 0;
124280304Sjkim    int verify_retcode = 0;
125280304Sjkim    int rr_print = 0, rr_allorfirst = -1;
126280304Sjkim    STACK_OF(OPENSSL_STRING) *rr_to = NULL, *rr_from = NULL;
127280304Sjkim    CMS_ReceiptRequest *rr = NULL;
128280304Sjkim    char *to = NULL, *from = NULL, *subject = NULL;
129280304Sjkim    char *CAfile = NULL, *CApath = NULL;
130280304Sjkim    char *passargin = NULL, *passin = NULL;
131280304Sjkim    char *inrand = NULL;
132280304Sjkim    int need_rand = 0;
133280304Sjkim    const EVP_MD *sign_md = NULL;
134280304Sjkim    int informat = FORMAT_SMIME, outformat = FORMAT_SMIME;
135280304Sjkim    int rctformat = FORMAT_SMIME, keyform = FORMAT_PEM;
136280304Sjkim# ifndef OPENSSL_NO_ENGINE
137280304Sjkim    char *engine = NULL;
138280304Sjkim# endif
139280304Sjkim    unsigned char *secret_key = NULL, *secret_keyid = NULL;
140280304Sjkim    unsigned char *pwri_pass = NULL, *pwri_tmp = NULL;
141280304Sjkim    size_t secret_keylen = 0, secret_keyidlen = 0;
142183234Ssimon
143280304Sjkim    ASN1_OBJECT *econtent_type = NULL;
144183234Ssimon
145280304Sjkim    X509_VERIFY_PARAM *vpm = NULL;
146183234Ssimon
147280304Sjkim    args = argv + 1;
148280304Sjkim    ret = 1;
149183234Ssimon
150280304Sjkim    apps_startup();
151183234Ssimon
152280304Sjkim    if (bio_err == NULL) {
153280304Sjkim        if ((bio_err = BIO_new(BIO_s_file())) != NULL)
154280304Sjkim            BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
155280304Sjkim    }
156183234Ssimon
157280304Sjkim    if (!load_config(bio_err, NULL))
158280304Sjkim        goto end;
159183234Ssimon
160280304Sjkim    while (!badarg && *args && *args[0] == '-') {
161280304Sjkim        if (!strcmp(*args, "-encrypt"))
162280304Sjkim            operation = SMIME_ENCRYPT;
163280304Sjkim        else if (!strcmp(*args, "-decrypt"))
164280304Sjkim            operation = SMIME_DECRYPT;
165280304Sjkim        else if (!strcmp(*args, "-sign"))
166280304Sjkim            operation = SMIME_SIGN;
167280304Sjkim        else if (!strcmp(*args, "-sign_receipt"))
168280304Sjkim            operation = SMIME_SIGN_RECEIPT;
169280304Sjkim        else if (!strcmp(*args, "-resign"))
170280304Sjkim            operation = SMIME_RESIGN;
171280304Sjkim        else if (!strcmp(*args, "-verify"))
172280304Sjkim            operation = SMIME_VERIFY;
173280304Sjkim        else if (!strcmp(*args, "-verify_retcode"))
174280304Sjkim            verify_retcode = 1;
175280304Sjkim        else if (!strcmp(*args, "-verify_receipt")) {
176280304Sjkim            operation = SMIME_VERIFY_RECEIPT;
177280304Sjkim            if (!args[1])
178280304Sjkim                goto argerr;
179280304Sjkim            args++;
180280304Sjkim            rctfile = *args;
181280304Sjkim        } else if (!strcmp(*args, "-cmsout"))
182280304Sjkim            operation = SMIME_CMSOUT;
183280304Sjkim        else if (!strcmp(*args, "-data_out"))
184280304Sjkim            operation = SMIME_DATAOUT;
185280304Sjkim        else if (!strcmp(*args, "-data_create"))
186280304Sjkim            operation = SMIME_DATA_CREATE;
187280304Sjkim        else if (!strcmp(*args, "-digest_verify"))
188280304Sjkim            operation = SMIME_DIGEST_VERIFY;
189280304Sjkim        else if (!strcmp(*args, "-digest_create"))
190280304Sjkim            operation = SMIME_DIGEST_CREATE;
191280304Sjkim        else if (!strcmp(*args, "-compress"))
192280304Sjkim            operation = SMIME_COMPRESS;
193280304Sjkim        else if (!strcmp(*args, "-uncompress"))
194280304Sjkim            operation = SMIME_UNCOMPRESS;
195280304Sjkim        else if (!strcmp(*args, "-EncryptedData_decrypt"))
196280304Sjkim            operation = SMIME_ENCRYPTED_DECRYPT;
197280304Sjkim        else if (!strcmp(*args, "-EncryptedData_encrypt"))
198280304Sjkim            operation = SMIME_ENCRYPTED_ENCRYPT;
199280304Sjkim# ifndef OPENSSL_NO_DES
200280304Sjkim        else if (!strcmp(*args, "-des3"))
201280304Sjkim            cipher = EVP_des_ede3_cbc();
202280304Sjkim        else if (!strcmp(*args, "-des"))
203280304Sjkim            cipher = EVP_des_cbc();
204280304Sjkim# endif
205280304Sjkim# ifndef OPENSSL_NO_SEED
206280304Sjkim        else if (!strcmp(*args, "-seed"))
207280304Sjkim            cipher = EVP_seed_cbc();
208280304Sjkim# endif
209280304Sjkim# ifndef OPENSSL_NO_RC2
210280304Sjkim        else if (!strcmp(*args, "-rc2-40"))
211280304Sjkim            cipher = EVP_rc2_40_cbc();
212280304Sjkim        else if (!strcmp(*args, "-rc2-128"))
213280304Sjkim            cipher = EVP_rc2_cbc();
214280304Sjkim        else if (!strcmp(*args, "-rc2-64"))
215280304Sjkim            cipher = EVP_rc2_64_cbc();
216280304Sjkim# endif
217280304Sjkim# ifndef OPENSSL_NO_AES
218280304Sjkim        else if (!strcmp(*args, "-aes128"))
219280304Sjkim            cipher = EVP_aes_128_cbc();
220280304Sjkim        else if (!strcmp(*args, "-aes192"))
221280304Sjkim            cipher = EVP_aes_192_cbc();
222280304Sjkim        else if (!strcmp(*args, "-aes256"))
223280304Sjkim            cipher = EVP_aes_256_cbc();
224280304Sjkim# endif
225280304Sjkim# ifndef OPENSSL_NO_CAMELLIA
226280304Sjkim        else if (!strcmp(*args, "-camellia128"))
227280304Sjkim            cipher = EVP_camellia_128_cbc();
228280304Sjkim        else if (!strcmp(*args, "-camellia192"))
229280304Sjkim            cipher = EVP_camellia_192_cbc();
230280304Sjkim        else if (!strcmp(*args, "-camellia256"))
231280304Sjkim            cipher = EVP_camellia_256_cbc();
232280304Sjkim# endif
233280304Sjkim        else if (!strcmp(*args, "-debug_decrypt"))
234280304Sjkim            flags |= CMS_DEBUG_DECRYPT;
235280304Sjkim        else if (!strcmp(*args, "-text"))
236280304Sjkim            flags |= CMS_TEXT;
237280304Sjkim        else if (!strcmp(*args, "-nointern"))
238280304Sjkim            flags |= CMS_NOINTERN;
239280304Sjkim        else if (!strcmp(*args, "-noverify")
240280304Sjkim                 || !strcmp(*args, "-no_signer_cert_verify"))
241280304Sjkim            flags |= CMS_NO_SIGNER_CERT_VERIFY;
242280304Sjkim        else if (!strcmp(*args, "-nocerts"))
243280304Sjkim            flags |= CMS_NOCERTS;
244280304Sjkim        else if (!strcmp(*args, "-noattr"))
245280304Sjkim            flags |= CMS_NOATTR;
246280304Sjkim        else if (!strcmp(*args, "-nodetach"))
247280304Sjkim            flags &= ~CMS_DETACHED;
248280304Sjkim        else if (!strcmp(*args, "-nosmimecap"))
249280304Sjkim            flags |= CMS_NOSMIMECAP;
250280304Sjkim        else if (!strcmp(*args, "-binary"))
251280304Sjkim            flags |= CMS_BINARY;
252280304Sjkim        else if (!strcmp(*args, "-keyid"))
253280304Sjkim            flags |= CMS_USE_KEYID;
254280304Sjkim        else if (!strcmp(*args, "-nosigs"))
255280304Sjkim            flags |= CMS_NOSIGS;
256280304Sjkim        else if (!strcmp(*args, "-no_content_verify"))
257280304Sjkim            flags |= CMS_NO_CONTENT_VERIFY;
258280304Sjkim        else if (!strcmp(*args, "-no_attr_verify"))
259280304Sjkim            flags |= CMS_NO_ATTR_VERIFY;
260280304Sjkim        else if (!strcmp(*args, "-stream"))
261280304Sjkim            flags |= CMS_STREAM;
262280304Sjkim        else if (!strcmp(*args, "-indef"))
263280304Sjkim            flags |= CMS_STREAM;
264280304Sjkim        else if (!strcmp(*args, "-noindef"))
265280304Sjkim            flags &= ~CMS_STREAM;
266280304Sjkim        else if (!strcmp(*args, "-nooldmime"))
267280304Sjkim            flags |= CMS_NOOLDMIMETYPE;
268280304Sjkim        else if (!strcmp(*args, "-crlfeol"))
269280304Sjkim            flags |= CMS_CRLFEOL;
270280304Sjkim        else if (!strcmp(*args, "-noout"))
271280304Sjkim            noout = 1;
272280304Sjkim        else if (!strcmp(*args, "-receipt_request_print"))
273280304Sjkim            rr_print = 1;
274280304Sjkim        else if (!strcmp(*args, "-receipt_request_all"))
275280304Sjkim            rr_allorfirst = 0;
276280304Sjkim        else if (!strcmp(*args, "-receipt_request_first"))
277280304Sjkim            rr_allorfirst = 1;
278280304Sjkim        else if (!strcmp(*args, "-receipt_request_from")) {
279280304Sjkim            if (!args[1])
280280304Sjkim                goto argerr;
281280304Sjkim            args++;
282280304Sjkim            if (!rr_from)
283280304Sjkim                rr_from = sk_OPENSSL_STRING_new_null();
284280304Sjkim            sk_OPENSSL_STRING_push(rr_from, *args);
285280304Sjkim        } else if (!strcmp(*args, "-receipt_request_to")) {
286280304Sjkim            if (!args[1])
287280304Sjkim                goto argerr;
288280304Sjkim            args++;
289280304Sjkim            if (!rr_to)
290280304Sjkim                rr_to = sk_OPENSSL_STRING_new_null();
291280304Sjkim            sk_OPENSSL_STRING_push(rr_to, *args);
292280304Sjkim        } else if (!strcmp(*args, "-print")) {
293280304Sjkim            noout = 1;
294280304Sjkim            print = 1;
295280304Sjkim        } else if (!strcmp(*args, "-secretkey")) {
296280304Sjkim            long ltmp;
297280304Sjkim            if (!args[1])
298280304Sjkim                goto argerr;
299280304Sjkim            args++;
300280304Sjkim            secret_key = string_to_hex(*args, &ltmp);
301280304Sjkim            if (!secret_key) {
302280304Sjkim                BIO_printf(bio_err, "Invalid key %s\n", *args);
303280304Sjkim                goto argerr;
304280304Sjkim            }
305280304Sjkim            secret_keylen = (size_t)ltmp;
306280304Sjkim        } else if (!strcmp(*args, "-secretkeyid")) {
307280304Sjkim            long ltmp;
308280304Sjkim            if (!args[1])
309280304Sjkim                goto argerr;
310280304Sjkim            args++;
311280304Sjkim            secret_keyid = string_to_hex(*args, &ltmp);
312280304Sjkim            if (!secret_keyid) {
313280304Sjkim                BIO_printf(bio_err, "Invalid id %s\n", *args);
314280304Sjkim                goto argerr;
315280304Sjkim            }
316280304Sjkim            secret_keyidlen = (size_t)ltmp;
317280304Sjkim        } else if (!strcmp(*args, "-pwri_password")) {
318280304Sjkim            if (!args[1])
319280304Sjkim                goto argerr;
320280304Sjkim            args++;
321280304Sjkim            pwri_pass = (unsigned char *)*args;
322280304Sjkim        } else if (!strcmp(*args, "-econtent_type")) {
323280304Sjkim            if (!args[1])
324280304Sjkim                goto argerr;
325280304Sjkim            args++;
326280304Sjkim            econtent_type = OBJ_txt2obj(*args, 0);
327280304Sjkim            if (!econtent_type) {
328280304Sjkim                BIO_printf(bio_err, "Invalid OID %s\n", *args);
329280304Sjkim                goto argerr;
330280304Sjkim            }
331280304Sjkim        } else if (!strcmp(*args, "-rand")) {
332280304Sjkim            if (!args[1])
333280304Sjkim                goto argerr;
334280304Sjkim            args++;
335280304Sjkim            inrand = *args;
336280304Sjkim            need_rand = 1;
337280304Sjkim        }
338280304Sjkim# ifndef OPENSSL_NO_ENGINE
339280304Sjkim        else if (!strcmp(*args, "-engine")) {
340280304Sjkim            if (!args[1])
341280304Sjkim                goto argerr;
342280304Sjkim            engine = *++args;
343280304Sjkim        }
344280304Sjkim# endif
345280304Sjkim        else if (!strcmp(*args, "-passin")) {
346280304Sjkim            if (!args[1])
347280304Sjkim                goto argerr;
348280304Sjkim            passargin = *++args;
349280304Sjkim        } else if (!strcmp(*args, "-to")) {
350280304Sjkim            if (!args[1])
351280304Sjkim                goto argerr;
352280304Sjkim            to = *++args;
353280304Sjkim        } else if (!strcmp(*args, "-from")) {
354280304Sjkim            if (!args[1])
355280304Sjkim                goto argerr;
356280304Sjkim            from = *++args;
357280304Sjkim        } else if (!strcmp(*args, "-subject")) {
358280304Sjkim            if (!args[1])
359280304Sjkim                goto argerr;
360280304Sjkim            subject = *++args;
361280304Sjkim        } else if (!strcmp(*args, "-signer")) {
362280304Sjkim            if (!args[1])
363280304Sjkim                goto argerr;
364280304Sjkim            /* If previous -signer argument add signer to list */
365183234Ssimon
366280304Sjkim            if (signerfile) {
367280304Sjkim                if (!sksigners)
368280304Sjkim                    sksigners = sk_OPENSSL_STRING_new_null();
369280304Sjkim                sk_OPENSSL_STRING_push(sksigners, signerfile);
370280304Sjkim                if (!keyfile)
371280304Sjkim                    keyfile = signerfile;
372280304Sjkim                if (!skkeys)
373280304Sjkim                    skkeys = sk_OPENSSL_STRING_new_null();
374280304Sjkim                sk_OPENSSL_STRING_push(skkeys, keyfile);
375280304Sjkim                keyfile = NULL;
376280304Sjkim            }
377280304Sjkim            signerfile = *++args;
378280304Sjkim        } else if (!strcmp(*args, "-recip")) {
379280304Sjkim            if (!args[1])
380280304Sjkim                goto argerr;
381280304Sjkim            recipfile = *++args;
382280304Sjkim        } else if (!strcmp(*args, "-certsout")) {
383280304Sjkim            if (!args[1])
384280304Sjkim                goto argerr;
385280304Sjkim            certsoutfile = *++args;
386280304Sjkim        } else if (!strcmp(*args, "-md")) {
387280304Sjkim            if (!args[1])
388280304Sjkim                goto argerr;
389280304Sjkim            sign_md = EVP_get_digestbyname(*++args);
390280304Sjkim            if (sign_md == NULL) {
391280304Sjkim                BIO_printf(bio_err, "Unknown digest %s\n", *args);
392280304Sjkim                goto argerr;
393280304Sjkim            }
394280304Sjkim        } else if (!strcmp(*args, "-inkey")) {
395280304Sjkim            if (!args[1])
396280304Sjkim                goto argerr;
397280304Sjkim            /* If previous -inkey arument add signer to list */
398280304Sjkim            if (keyfile) {
399280304Sjkim                if (!signerfile) {
400280304Sjkim                    BIO_puts(bio_err, "Illegal -inkey without -signer\n");
401280304Sjkim                    goto argerr;
402280304Sjkim                }
403280304Sjkim                if (!sksigners)
404280304Sjkim                    sksigners = sk_OPENSSL_STRING_new_null();
405280304Sjkim                sk_OPENSSL_STRING_push(sksigners, signerfile);
406280304Sjkim                signerfile = NULL;
407280304Sjkim                if (!skkeys)
408280304Sjkim                    skkeys = sk_OPENSSL_STRING_new_null();
409280304Sjkim                sk_OPENSSL_STRING_push(skkeys, keyfile);
410280304Sjkim            }
411280304Sjkim            keyfile = *++args;
412280304Sjkim        } else if (!strcmp(*args, "-keyform")) {
413280304Sjkim            if (!args[1])
414280304Sjkim                goto argerr;
415280304Sjkim            keyform = str2fmt(*++args);
416280304Sjkim        } else if (!strcmp(*args, "-rctform")) {
417280304Sjkim            if (!args[1])
418280304Sjkim                goto argerr;
419280304Sjkim            rctformat = str2fmt(*++args);
420280304Sjkim        } else if (!strcmp(*args, "-certfile")) {
421280304Sjkim            if (!args[1])
422280304Sjkim                goto argerr;
423280304Sjkim            certfile = *++args;
424280304Sjkim        } else if (!strcmp(*args, "-CAfile")) {
425280304Sjkim            if (!args[1])
426280304Sjkim                goto argerr;
427280304Sjkim            CAfile = *++args;
428280304Sjkim        } else if (!strcmp(*args, "-CApath")) {
429280304Sjkim            if (!args[1])
430280304Sjkim                goto argerr;
431280304Sjkim            CApath = *++args;
432280304Sjkim        } else if (!strcmp(*args, "-in")) {
433280304Sjkim            if (!args[1])
434280304Sjkim                goto argerr;
435280304Sjkim            infile = *++args;
436280304Sjkim        } else if (!strcmp(*args, "-inform")) {
437280304Sjkim            if (!args[1])
438280304Sjkim                goto argerr;
439280304Sjkim            informat = str2fmt(*++args);
440280304Sjkim        } else if (!strcmp(*args, "-outform")) {
441280304Sjkim            if (!args[1])
442280304Sjkim                goto argerr;
443280304Sjkim            outformat = str2fmt(*++args);
444280304Sjkim        } else if (!strcmp(*args, "-out")) {
445280304Sjkim            if (!args[1])
446280304Sjkim                goto argerr;
447280304Sjkim            outfile = *++args;
448280304Sjkim        } else if (!strcmp(*args, "-content")) {
449280304Sjkim            if (!args[1])
450280304Sjkim                goto argerr;
451280304Sjkim            contfile = *++args;
452280304Sjkim        } else if (args_verify(&args, NULL, &badarg, bio_err, &vpm))
453280304Sjkim            continue;
454280304Sjkim        else if ((cipher = EVP_get_cipherbyname(*args + 1)) == NULL)
455280304Sjkim            badarg = 1;
456280304Sjkim        args++;
457280304Sjkim    }
458183234Ssimon
459280304Sjkim    if (((rr_allorfirst != -1) || rr_from) && !rr_to) {
460280304Sjkim        BIO_puts(bio_err, "No Signed Receipts Recipients\n");
461280304Sjkim        goto argerr;
462280304Sjkim    }
463183234Ssimon
464280304Sjkim    if (!(operation & SMIME_SIGNERS) && (rr_to || rr_from)) {
465280304Sjkim        BIO_puts(bio_err, "Signed receipts only allowed with -sign\n");
466280304Sjkim        goto argerr;
467280304Sjkim    }
468280304Sjkim    if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) {
469280304Sjkim        BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
470280304Sjkim        goto argerr;
471280304Sjkim    }
472183234Ssimon
473280304Sjkim    if (operation & SMIME_SIGNERS) {
474280304Sjkim        if (keyfile && !signerfile) {
475280304Sjkim            BIO_puts(bio_err, "Illegal -inkey without -signer\n");
476280304Sjkim            goto argerr;
477280304Sjkim        }
478280304Sjkim        /* Check to see if any final signer needs to be appended */
479280304Sjkim        if (signerfile) {
480280304Sjkim            if (!sksigners)
481280304Sjkim                sksigners = sk_OPENSSL_STRING_new_null();
482280304Sjkim            sk_OPENSSL_STRING_push(sksigners, signerfile);
483280304Sjkim            if (!skkeys)
484280304Sjkim                skkeys = sk_OPENSSL_STRING_new_null();
485280304Sjkim            if (!keyfile)
486280304Sjkim                keyfile = signerfile;
487280304Sjkim            sk_OPENSSL_STRING_push(skkeys, keyfile);
488280304Sjkim        }
489280304Sjkim        if (!sksigners) {
490280304Sjkim            BIO_printf(bio_err, "No signer certificate specified\n");
491280304Sjkim            badarg = 1;
492280304Sjkim        }
493280304Sjkim        signerfile = NULL;
494280304Sjkim        keyfile = NULL;
495280304Sjkim        need_rand = 1;
496280304Sjkim    }
497183234Ssimon
498280304Sjkim    else if (operation == SMIME_DECRYPT) {
499280304Sjkim        if (!recipfile && !keyfile && !secret_key && !pwri_pass) {
500280304Sjkim            BIO_printf(bio_err,
501280304Sjkim                       "No recipient certificate or key specified\n");
502280304Sjkim            badarg = 1;
503280304Sjkim        }
504280304Sjkim    } else if (operation == SMIME_ENCRYPT) {
505280304Sjkim        if (!*args && !secret_key && !pwri_pass) {
506280304Sjkim            BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
507280304Sjkim            badarg = 1;
508280304Sjkim        }
509280304Sjkim        need_rand = 1;
510280304Sjkim    } else if (!operation)
511280304Sjkim        badarg = 1;
512183234Ssimon
513280304Sjkim    if (badarg) {
514280304Sjkim argerr:
515280304Sjkim        BIO_printf(bio_err, "Usage cms [options] cert.pem ...\n");
516280304Sjkim        BIO_printf(bio_err, "where options are\n");
517280304Sjkim        BIO_printf(bio_err, "-encrypt       encrypt message\n");
518280304Sjkim        BIO_printf(bio_err, "-decrypt       decrypt encrypted message\n");
519280304Sjkim        BIO_printf(bio_err, "-sign          sign message\n");
520280304Sjkim        BIO_printf(bio_err, "-verify        verify signed message\n");
521280304Sjkim        BIO_printf(bio_err, "-cmsout        output CMS structure\n");
522280304Sjkim# ifndef OPENSSL_NO_DES
523280304Sjkim        BIO_printf(bio_err, "-des3          encrypt with triple DES\n");
524280304Sjkim        BIO_printf(bio_err, "-des           encrypt with DES\n");
525280304Sjkim# endif
526280304Sjkim# ifndef OPENSSL_NO_SEED
527280304Sjkim        BIO_printf(bio_err, "-seed          encrypt with SEED\n");
528280304Sjkim# endif
529280304Sjkim# ifndef OPENSSL_NO_RC2
530280304Sjkim        BIO_printf(bio_err, "-rc2-40        encrypt with RC2-40 (default)\n");
531280304Sjkim        BIO_printf(bio_err, "-rc2-64        encrypt with RC2-64\n");
532280304Sjkim        BIO_printf(bio_err, "-rc2-128       encrypt with RC2-128\n");
533280304Sjkim# endif
534280304Sjkim# ifndef OPENSSL_NO_AES
535280304Sjkim        BIO_printf(bio_err, "-aes128, -aes192, -aes256\n");
536280304Sjkim        BIO_printf(bio_err,
537280304Sjkim                   "               encrypt PEM output with cbc aes\n");
538280304Sjkim# endif
539280304Sjkim# ifndef OPENSSL_NO_CAMELLIA
540280304Sjkim        BIO_printf(bio_err, "-camellia128, -camellia192, -camellia256\n");
541280304Sjkim        BIO_printf(bio_err,
542280304Sjkim                   "               encrypt PEM output with cbc camellia\n");
543280304Sjkim# endif
544280304Sjkim        BIO_printf(bio_err,
545280304Sjkim                   "-nointern      don't search certificates in message for signer\n");
546280304Sjkim        BIO_printf(bio_err,
547280304Sjkim                   "-nosigs        don't verify message signature\n");
548280304Sjkim        BIO_printf(bio_err,
549280304Sjkim                   "-noverify      don't verify signers certificate\n");
550280304Sjkim        BIO_printf(bio_err,
551280304Sjkim                   "-nocerts       don't include signers certificate when signing\n");
552280304Sjkim        BIO_printf(bio_err, "-nodetach      use opaque signing\n");
553280304Sjkim        BIO_printf(bio_err,
554280304Sjkim                   "-noattr        don't include any signed attributes\n");
555280304Sjkim        BIO_printf(bio_err,
556280304Sjkim                   "-binary        don't translate message to text\n");
557280304Sjkim        BIO_printf(bio_err, "-certfile file other certificates file\n");
558280304Sjkim        BIO_printf(bio_err, "-certsout file certificate output file\n");
559280304Sjkim        BIO_printf(bio_err, "-signer file   signer certificate file\n");
560280304Sjkim        BIO_printf(bio_err,
561280304Sjkim                   "-recip  file   recipient certificate file for decryption\n");
562280304Sjkim        BIO_printf(bio_err, "-keyid         use subject key identifier\n");
563280304Sjkim        BIO_printf(bio_err, "-in file       input file\n");
564280304Sjkim        BIO_printf(bio_err,
565280304Sjkim                   "-inform arg    input format SMIME (default), PEM or DER\n");
566280304Sjkim        BIO_printf(bio_err,
567280304Sjkim                   "-inkey file    input private key (if not signer or recipient)\n");
568280304Sjkim        BIO_printf(bio_err,
569280304Sjkim                   "-keyform arg   input private key format (PEM or ENGINE)\n");
570280304Sjkim        BIO_printf(bio_err, "-out file      output file\n");
571280304Sjkim        BIO_printf(bio_err,
572280304Sjkim                   "-outform arg   output format SMIME (default), PEM or DER\n");
573280304Sjkim        BIO_printf(bio_err,
574280304Sjkim                   "-content file  supply or override content for detached signature\n");
575280304Sjkim        BIO_printf(bio_err, "-to addr       to address\n");
576280304Sjkim        BIO_printf(bio_err, "-from ad       from address\n");
577280304Sjkim        BIO_printf(bio_err, "-subject s     subject\n");
578280304Sjkim        BIO_printf(bio_err,
579280304Sjkim                   "-text          include or delete text MIME headers\n");
580280304Sjkim        BIO_printf(bio_err,
581280304Sjkim                   "-CApath dir    trusted certificates directory\n");
582280304Sjkim        BIO_printf(bio_err, "-CAfile file   trusted certificates file\n");
583280304Sjkim        BIO_printf(bio_err,
584284285Sjkim                   "-no_alt_chains only ever use the first certificate chain found\n");
585284285Sjkim        BIO_printf(bio_err,
586280304Sjkim                   "-crl_check     check revocation status of signer's certificate using CRLs\n");
587280304Sjkim        BIO_printf(bio_err,
588280304Sjkim                   "-crl_check_all check revocation status of signer's certificate chain using CRLs\n");
589280304Sjkim# ifndef OPENSSL_NO_ENGINE
590280304Sjkim        BIO_printf(bio_err,
591280304Sjkim                   "-engine e      use engine e, possibly a hardware device.\n");
592280304Sjkim# endif
593280304Sjkim        BIO_printf(bio_err, "-passin arg    input file pass phrase source\n");
594280304Sjkim        BIO_printf(bio_err, "-rand file%cfile%c...\n", LIST_SEPARATOR_CHAR,
595280304Sjkim                   LIST_SEPARATOR_CHAR);
596280304Sjkim        BIO_printf(bio_err,
597280304Sjkim                   "               load the file (or the files in the directory) into\n");
598280304Sjkim        BIO_printf(bio_err, "               the random number generator\n");
599280304Sjkim        BIO_printf(bio_err,
600280304Sjkim                   "cert.pem       recipient certificate(s) for encryption\n");
601280304Sjkim        goto end;
602280304Sjkim    }
603280304Sjkim# ifndef OPENSSL_NO_ENGINE
604280304Sjkim    e = setup_engine(bio_err, engine, 0);
605280304Sjkim# endif
606183234Ssimon
607280304Sjkim    if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
608280304Sjkim        BIO_printf(bio_err, "Error getting password\n");
609280304Sjkim        goto end;
610280304Sjkim    }
611183234Ssimon
612280304Sjkim    if (need_rand) {
613280304Sjkim        app_RAND_load_file(NULL, bio_err, (inrand != NULL));
614280304Sjkim        if (inrand != NULL)
615280304Sjkim            BIO_printf(bio_err, "%ld semi-random bytes loaded\n",
616280304Sjkim                       app_RAND_load_files(inrand));
617280304Sjkim    }
618183234Ssimon
619280304Sjkim    ret = 2;
620183234Ssimon
621280304Sjkim    if (!(operation & SMIME_SIGNERS))
622280304Sjkim        flags &= ~CMS_DETACHED;
623183234Ssimon
624280304Sjkim    if (operation & SMIME_OP) {
625280304Sjkim        if (outformat == FORMAT_ASN1)
626280304Sjkim            outmode = "wb";
627280304Sjkim    } else {
628280304Sjkim        if (flags & CMS_BINARY)
629280304Sjkim            outmode = "wb";
630280304Sjkim    }
631183234Ssimon
632280304Sjkim    if (operation & SMIME_IP) {
633280304Sjkim        if (informat == FORMAT_ASN1)
634280304Sjkim            inmode = "rb";
635280304Sjkim    } else {
636280304Sjkim        if (flags & CMS_BINARY)
637280304Sjkim            inmode = "rb";
638280304Sjkim    }
639183234Ssimon
640280304Sjkim    if (operation == SMIME_ENCRYPT) {
641280304Sjkim        if (!cipher) {
642280304Sjkim# ifndef OPENSSL_NO_DES
643280304Sjkim            cipher = EVP_des_ede3_cbc();
644280304Sjkim# else
645280304Sjkim            BIO_printf(bio_err, "No cipher selected\n");
646280304Sjkim            goto end;
647280304Sjkim# endif
648280304Sjkim        }
649183234Ssimon
650280304Sjkim        if (secret_key && !secret_keyid) {
651280304Sjkim            BIO_printf(bio_err, "No secret key id\n");
652280304Sjkim            goto end;
653280304Sjkim        }
654183234Ssimon
655280304Sjkim        if (*args)
656280304Sjkim            encerts = sk_X509_new_null();
657280304Sjkim        while (*args) {
658280304Sjkim            if (!(cert = load_cert(bio_err, *args, FORMAT_PEM,
659280304Sjkim                                   NULL, e, "recipient certificate file")))
660280304Sjkim                goto end;
661280304Sjkim            sk_X509_push(encerts, cert);
662280304Sjkim            cert = NULL;
663280304Sjkim            args++;
664280304Sjkim        }
665280304Sjkim    }
666183234Ssimon
667280304Sjkim    if (certfile) {
668280304Sjkim        if (!(other = load_certs(bio_err, certfile, FORMAT_PEM, NULL,
669280304Sjkim                                 e, "certificate file"))) {
670280304Sjkim            ERR_print_errors(bio_err);
671280304Sjkim            goto end;
672280304Sjkim        }
673280304Sjkim    }
674183234Ssimon
675280304Sjkim    if (recipfile && (operation == SMIME_DECRYPT)) {
676280304Sjkim        if (!(recip = load_cert(bio_err, recipfile, FORMAT_PEM, NULL,
677280304Sjkim                                e, "recipient certificate file"))) {
678280304Sjkim            ERR_print_errors(bio_err);
679280304Sjkim            goto end;
680280304Sjkim        }
681280304Sjkim    }
682183234Ssimon
683280304Sjkim    if (operation == SMIME_SIGN_RECEIPT) {
684280304Sjkim        if (!(signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL,
685280304Sjkim                                 e, "receipt signer certificate file"))) {
686280304Sjkim            ERR_print_errors(bio_err);
687280304Sjkim            goto end;
688280304Sjkim        }
689280304Sjkim    }
690183234Ssimon
691280304Sjkim    if (operation == SMIME_DECRYPT) {
692280304Sjkim        if (!keyfile)
693280304Sjkim            keyfile = recipfile;
694280304Sjkim    } else if ((operation == SMIME_SIGN) || (operation == SMIME_SIGN_RECEIPT)) {
695280304Sjkim        if (!keyfile)
696280304Sjkim            keyfile = signerfile;
697280304Sjkim    } else
698280304Sjkim        keyfile = NULL;
699183234Ssimon
700280304Sjkim    if (keyfile) {
701280304Sjkim        key = load_key(bio_err, keyfile, keyform, 0, passin, e,
702280304Sjkim                       "signing key file");
703280304Sjkim        if (!key)
704280304Sjkim            goto end;
705280304Sjkim    }
706183234Ssimon
707280304Sjkim    if (infile) {
708280304Sjkim        if (!(in = BIO_new_file(infile, inmode))) {
709280304Sjkim            BIO_printf(bio_err, "Can't open input file %s\n", infile);
710280304Sjkim            goto end;
711280304Sjkim        }
712280304Sjkim    } else
713280304Sjkim        in = BIO_new_fp(stdin, BIO_NOCLOSE);
714183234Ssimon
715280304Sjkim    if (operation & SMIME_IP) {
716280304Sjkim        if (informat == FORMAT_SMIME)
717280304Sjkim            cms = SMIME_read_CMS(in, &indata);
718280304Sjkim        else if (informat == FORMAT_PEM)
719280304Sjkim            cms = PEM_read_bio_CMS(in, NULL, NULL, NULL);
720280304Sjkim        else if (informat == FORMAT_ASN1)
721280304Sjkim            cms = d2i_CMS_bio(in, NULL);
722280304Sjkim        else {
723280304Sjkim            BIO_printf(bio_err, "Bad input format for CMS file\n");
724280304Sjkim            goto end;
725280304Sjkim        }
726183234Ssimon
727280304Sjkim        if (!cms) {
728280304Sjkim            BIO_printf(bio_err, "Error reading S/MIME message\n");
729280304Sjkim            goto end;
730280304Sjkim        }
731280304Sjkim        if (contfile) {
732280304Sjkim            BIO_free(indata);
733280304Sjkim            if (!(indata = BIO_new_file(contfile, "rb"))) {
734280304Sjkim                BIO_printf(bio_err, "Can't read content file %s\n", contfile);
735280304Sjkim                goto end;
736280304Sjkim            }
737280304Sjkim        }
738280304Sjkim        if (certsoutfile) {
739280304Sjkim            STACK_OF(X509) *allcerts;
740280304Sjkim            allcerts = CMS_get1_certs(cms);
741280304Sjkim            if (!save_certs(certsoutfile, allcerts)) {
742280304Sjkim                BIO_printf(bio_err,
743280304Sjkim                           "Error writing certs to %s\n", certsoutfile);
744280304Sjkim                ret = 5;
745280304Sjkim                goto end;
746280304Sjkim            }
747280304Sjkim            sk_X509_pop_free(allcerts, X509_free);
748280304Sjkim        }
749280304Sjkim    }
750183234Ssimon
751280304Sjkim    if (rctfile) {
752280304Sjkim        char *rctmode = (rctformat == FORMAT_ASN1) ? "rb" : "r";
753280304Sjkim        if (!(rctin = BIO_new_file(rctfile, rctmode))) {
754280304Sjkim            BIO_printf(bio_err, "Can't open receipt file %s\n", rctfile);
755280304Sjkim            goto end;
756280304Sjkim        }
757183234Ssimon
758280304Sjkim        if (rctformat == FORMAT_SMIME)
759280304Sjkim            rcms = SMIME_read_CMS(rctin, NULL);
760280304Sjkim        else if (rctformat == FORMAT_PEM)
761280304Sjkim            rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL);
762280304Sjkim        else if (rctformat == FORMAT_ASN1)
763280304Sjkim            rcms = d2i_CMS_bio(rctin, NULL);
764280304Sjkim        else {
765280304Sjkim            BIO_printf(bio_err, "Bad input format for receipt\n");
766280304Sjkim            goto end;
767280304Sjkim        }
768183234Ssimon
769280304Sjkim        if (!rcms) {
770280304Sjkim            BIO_printf(bio_err, "Error reading receipt\n");
771280304Sjkim            goto end;
772280304Sjkim        }
773280304Sjkim    }
774183234Ssimon
775280304Sjkim    if (outfile) {
776280304Sjkim        if (!(out = BIO_new_file(outfile, outmode))) {
777280304Sjkim            BIO_printf(bio_err, "Can't open output file %s\n", outfile);
778280304Sjkim            goto end;
779280304Sjkim        }
780280304Sjkim    } else {
781280304Sjkim        out = BIO_new_fp(stdout, BIO_NOCLOSE);
782280304Sjkim# ifdef OPENSSL_SYS_VMS
783280304Sjkim        {
784280304Sjkim            BIO *tmpbio = BIO_new(BIO_f_linebuffer());
785280304Sjkim            out = BIO_push(tmpbio, out);
786280304Sjkim        }
787280304Sjkim# endif
788280304Sjkim    }
789183234Ssimon
790280304Sjkim    if ((operation == SMIME_VERIFY) || (operation == SMIME_VERIFY_RECEIPT)) {
791280304Sjkim        if (!(store = setup_verify(bio_err, CAfile, CApath)))
792280304Sjkim            goto end;
793280304Sjkim        X509_STORE_set_verify_cb(store, cms_cb);
794280304Sjkim        if (vpm)
795280304Sjkim            X509_STORE_set1_param(store, vpm);
796280304Sjkim    }
797183234Ssimon
798280304Sjkim    ret = 3;
799183234Ssimon
800280304Sjkim    if (operation == SMIME_DATA_CREATE) {
801280304Sjkim        cms = CMS_data_create(in, flags);
802280304Sjkim    } else if (operation == SMIME_DIGEST_CREATE) {
803280304Sjkim        cms = CMS_digest_create(in, sign_md, flags);
804280304Sjkim    } else if (operation == SMIME_COMPRESS) {
805280304Sjkim        cms = CMS_compress(in, -1, flags);
806280304Sjkim    } else if (operation == SMIME_ENCRYPT) {
807280304Sjkim        flags |= CMS_PARTIAL;
808280304Sjkim        cms = CMS_encrypt(encerts, in, cipher, flags);
809280304Sjkim        if (!cms)
810280304Sjkim            goto end;
811280304Sjkim        if (secret_key) {
812280304Sjkim            if (!CMS_add0_recipient_key(cms, NID_undef,
813280304Sjkim                                        secret_key, secret_keylen,
814280304Sjkim                                        secret_keyid, secret_keyidlen,
815280304Sjkim                                        NULL, NULL, NULL))
816280304Sjkim                goto end;
817280304Sjkim            /* NULL these because call absorbs them */
818280304Sjkim            secret_key = NULL;
819280304Sjkim            secret_keyid = NULL;
820280304Sjkim        }
821280304Sjkim        if (pwri_pass) {
822280304Sjkim            pwri_tmp = (unsigned char *)BUF_strdup((char *)pwri_pass);
823280304Sjkim            if (!pwri_tmp)
824280304Sjkim                goto end;
825280304Sjkim            if (!CMS_add0_recipient_password(cms,
826280304Sjkim                                             -1, NID_undef, NID_undef,
827280304Sjkim                                             pwri_tmp, -1, NULL))
828280304Sjkim                goto end;
829280304Sjkim            pwri_tmp = NULL;
830280304Sjkim        }
831280304Sjkim        if (!(flags & CMS_STREAM)) {
832280304Sjkim            if (!CMS_final(cms, in, NULL, flags))
833280304Sjkim                goto end;
834280304Sjkim        }
835280304Sjkim    } else if (operation == SMIME_ENCRYPTED_ENCRYPT) {
836280304Sjkim        cms = CMS_EncryptedData_encrypt(in, cipher,
837280304Sjkim                                        secret_key, secret_keylen, flags);
838183234Ssimon
839280304Sjkim    } else if (operation == SMIME_SIGN_RECEIPT) {
840280304Sjkim        CMS_ContentInfo *srcms = NULL;
841280304Sjkim        STACK_OF(CMS_SignerInfo) *sis;
842280304Sjkim        CMS_SignerInfo *si;
843280304Sjkim        sis = CMS_get0_SignerInfos(cms);
844280304Sjkim        if (!sis)
845280304Sjkim            goto end;
846280304Sjkim        si = sk_CMS_SignerInfo_value(sis, 0);
847280304Sjkim        srcms = CMS_sign_receipt(si, signer, key, other, flags);
848280304Sjkim        if (!srcms)
849280304Sjkim            goto end;
850280304Sjkim        CMS_ContentInfo_free(cms);
851280304Sjkim        cms = srcms;
852280304Sjkim    } else if (operation & SMIME_SIGNERS) {
853280304Sjkim        int i;
854280304Sjkim        /*
855280304Sjkim         * If detached data content we enable streaming if S/MIME output
856280304Sjkim         * format.
857280304Sjkim         */
858280304Sjkim        if (operation == SMIME_SIGN) {
859183234Ssimon
860280304Sjkim            if (flags & CMS_DETACHED) {
861280304Sjkim                if (outformat == FORMAT_SMIME)
862280304Sjkim                    flags |= CMS_STREAM;
863280304Sjkim            }
864280304Sjkim            flags |= CMS_PARTIAL;
865280304Sjkim            cms = CMS_sign(NULL, NULL, other, in, flags);
866280304Sjkim            if (!cms)
867280304Sjkim                goto end;
868280304Sjkim            if (econtent_type)
869280304Sjkim                CMS_set1_eContentType(cms, econtent_type);
870183234Ssimon
871280304Sjkim            if (rr_to) {
872280304Sjkim                rr = make_receipt_request(rr_to, rr_allorfirst, rr_from);
873280304Sjkim                if (!rr) {
874280304Sjkim                    BIO_puts(bio_err,
875280304Sjkim                             "Signed Receipt Request Creation Error\n");
876280304Sjkim                    goto end;
877280304Sjkim                }
878280304Sjkim            }
879280304Sjkim        } else
880280304Sjkim            flags |= CMS_REUSE_DIGEST;
881280304Sjkim        for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) {
882280304Sjkim            CMS_SignerInfo *si;
883280304Sjkim            signerfile = sk_OPENSSL_STRING_value(sksigners, i);
884280304Sjkim            keyfile = sk_OPENSSL_STRING_value(skkeys, i);
885280304Sjkim            signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL,
886280304Sjkim                               e, "signer certificate");
887280304Sjkim            if (!signer)
888280304Sjkim                goto end;
889280304Sjkim            key = load_key(bio_err, keyfile, keyform, 0, passin, e,
890280304Sjkim                           "signing key file");
891280304Sjkim            if (!key)
892280304Sjkim                goto end;
893280304Sjkim            si = CMS_add1_signer(cms, signer, key, sign_md, flags);
894280304Sjkim            if (!si)
895280304Sjkim                goto end;
896280304Sjkim            if (rr && !CMS_add1_ReceiptRequest(si, rr))
897280304Sjkim                goto end;
898280304Sjkim            X509_free(signer);
899280304Sjkim            signer = NULL;
900280304Sjkim            EVP_PKEY_free(key);
901280304Sjkim            key = NULL;
902280304Sjkim        }
903280304Sjkim        /* If not streaming or resigning finalize structure */
904280304Sjkim        if ((operation == SMIME_SIGN) && !(flags & CMS_STREAM)) {
905280304Sjkim            if (!CMS_final(cms, in, NULL, flags))
906280304Sjkim                goto end;
907280304Sjkim        }
908280304Sjkim    }
909183234Ssimon
910280304Sjkim    if (!cms) {
911280304Sjkim        BIO_printf(bio_err, "Error creating CMS structure\n");
912280304Sjkim        goto end;
913280304Sjkim    }
914183234Ssimon
915280304Sjkim    ret = 4;
916280304Sjkim    if (operation == SMIME_DECRYPT) {
917280304Sjkim        if (flags & CMS_DEBUG_DECRYPT)
918280304Sjkim            CMS_decrypt(cms, NULL, NULL, NULL, NULL, flags);
919183234Ssimon
920280304Sjkim        if (secret_key) {
921280304Sjkim            if (!CMS_decrypt_set1_key(cms,
922280304Sjkim                                      secret_key, secret_keylen,
923280304Sjkim                                      secret_keyid, secret_keyidlen)) {
924280304Sjkim                BIO_puts(bio_err, "Error decrypting CMS using secret key\n");
925280304Sjkim                goto end;
926280304Sjkim            }
927280304Sjkim        }
928183234Ssimon
929280304Sjkim        if (key) {
930280304Sjkim            if (!CMS_decrypt_set1_pkey(cms, key, recip)) {
931280304Sjkim                BIO_puts(bio_err, "Error decrypting CMS using private key\n");
932280304Sjkim                goto end;
933280304Sjkim            }
934280304Sjkim        }
935183234Ssimon
936280304Sjkim        if (pwri_pass) {
937280304Sjkim            if (!CMS_decrypt_set1_password(cms, pwri_pass, -1)) {
938280304Sjkim                BIO_puts(bio_err, "Error decrypting CMS using password\n");
939280304Sjkim                goto end;
940280304Sjkim            }
941280304Sjkim        }
942238405Sjkim
943280304Sjkim        if (!CMS_decrypt(cms, NULL, NULL, indata, out, flags)) {
944280304Sjkim            BIO_printf(bio_err, "Error decrypting CMS structure\n");
945280304Sjkim            goto end;
946280304Sjkim        }
947280304Sjkim    } else if (operation == SMIME_DATAOUT) {
948280304Sjkim        if (!CMS_data(cms, out, flags))
949280304Sjkim            goto end;
950280304Sjkim    } else if (operation == SMIME_UNCOMPRESS) {
951280304Sjkim        if (!CMS_uncompress(cms, indata, out, flags))
952280304Sjkim            goto end;
953280304Sjkim    } else if (operation == SMIME_DIGEST_VERIFY) {
954280304Sjkim        if (CMS_digest_verify(cms, indata, out, flags) > 0)
955280304Sjkim            BIO_printf(bio_err, "Verification successful\n");
956280304Sjkim        else {
957280304Sjkim            BIO_printf(bio_err, "Verification failure\n");
958280304Sjkim            goto end;
959280304Sjkim        }
960280304Sjkim    } else if (operation == SMIME_ENCRYPTED_DECRYPT) {
961280304Sjkim        if (!CMS_EncryptedData_decrypt(cms, secret_key, secret_keylen,
962280304Sjkim                                       indata, out, flags))
963280304Sjkim            goto end;
964280304Sjkim    } else if (operation == SMIME_VERIFY) {
965280304Sjkim        if (CMS_verify(cms, other, store, indata, out, flags) > 0)
966280304Sjkim            BIO_printf(bio_err, "Verification successful\n");
967280304Sjkim        else {
968280304Sjkim            BIO_printf(bio_err, "Verification failure\n");
969280304Sjkim            if (verify_retcode)
970280304Sjkim                ret = verify_err + 32;
971280304Sjkim            goto end;
972280304Sjkim        }
973280304Sjkim        if (signerfile) {
974280304Sjkim            STACK_OF(X509) *signers;
975280304Sjkim            signers = CMS_get0_signers(cms);
976280304Sjkim            if (!save_certs(signerfile, signers)) {
977280304Sjkim                BIO_printf(bio_err,
978280304Sjkim                           "Error writing signers to %s\n", signerfile);
979280304Sjkim                ret = 5;
980280304Sjkim                goto end;
981280304Sjkim            }
982280304Sjkim            sk_X509_free(signers);
983280304Sjkim        }
984280304Sjkim        if (rr_print)
985280304Sjkim            receipt_request_print(bio_err, cms);
986280304Sjkim
987280304Sjkim    } else if (operation == SMIME_VERIFY_RECEIPT) {
988280304Sjkim        if (CMS_verify_receipt(rcms, cms, other, store, flags) > 0)
989280304Sjkim            BIO_printf(bio_err, "Verification successful\n");
990280304Sjkim        else {
991280304Sjkim            BIO_printf(bio_err, "Verification failure\n");
992280304Sjkim            goto end;
993280304Sjkim        }
994280304Sjkim    } else {
995280304Sjkim        if (noout) {
996280304Sjkim            if (print)
997280304Sjkim                CMS_ContentInfo_print_ctx(out, cms, 0, NULL);
998280304Sjkim        } else if (outformat == FORMAT_SMIME) {
999280304Sjkim            if (to)
1000280304Sjkim                BIO_printf(out, "To: %s\n", to);
1001280304Sjkim            if (from)
1002280304Sjkim                BIO_printf(out, "From: %s\n", from);
1003280304Sjkim            if (subject)
1004280304Sjkim                BIO_printf(out, "Subject: %s\n", subject);
1005280304Sjkim            if (operation == SMIME_RESIGN)
1006280304Sjkim                ret = SMIME_write_CMS(out, cms, indata, flags);
1007280304Sjkim            else
1008280304Sjkim                ret = SMIME_write_CMS(out, cms, in, flags);
1009280304Sjkim        } else if (outformat == FORMAT_PEM)
1010280304Sjkim            ret = PEM_write_bio_CMS_stream(out, cms, in, flags);
1011280304Sjkim        else if (outformat == FORMAT_ASN1)
1012280304Sjkim            ret = i2d_CMS_bio_stream(out, cms, in, flags);
1013280304Sjkim        else {
1014280304Sjkim            BIO_printf(bio_err, "Bad output format for CMS file\n");
1015280304Sjkim            goto end;
1016280304Sjkim        }
1017280304Sjkim        if (ret <= 0) {
1018280304Sjkim            ret = 6;
1019280304Sjkim            goto end;
1020280304Sjkim        }
1021280304Sjkim    }
1022280304Sjkim    ret = 0;
1023280304Sjkim end:
1024280304Sjkim    if (ret)
1025280304Sjkim        ERR_print_errors(bio_err);
1026280304Sjkim    if (need_rand)
1027280304Sjkim        app_RAND_write_file(NULL, bio_err);
1028280304Sjkim    sk_X509_pop_free(encerts, X509_free);
1029280304Sjkim    sk_X509_pop_free(other, X509_free);
1030280304Sjkim    if (vpm)
1031280304Sjkim        X509_VERIFY_PARAM_free(vpm);
1032280304Sjkim    if (sksigners)
1033280304Sjkim        sk_OPENSSL_STRING_free(sksigners);
1034280304Sjkim    if (skkeys)
1035280304Sjkim        sk_OPENSSL_STRING_free(skkeys);
1036280304Sjkim    if (secret_key)
1037280304Sjkim        OPENSSL_free(secret_key);
1038280304Sjkim    if (secret_keyid)
1039280304Sjkim        OPENSSL_free(secret_keyid);
1040280304Sjkim    if (pwri_tmp)
1041280304Sjkim        OPENSSL_free(pwri_tmp);
1042280304Sjkim    if (econtent_type)
1043280304Sjkim        ASN1_OBJECT_free(econtent_type);
1044280304Sjkim    if (rr)
1045280304Sjkim        CMS_ReceiptRequest_free(rr);
1046280304Sjkim    if (rr_to)
1047280304Sjkim        sk_OPENSSL_STRING_free(rr_to);
1048280304Sjkim    if (rr_from)
1049280304Sjkim        sk_OPENSSL_STRING_free(rr_from);
1050280304Sjkim    X509_STORE_free(store);
1051280304Sjkim    X509_free(cert);
1052280304Sjkim    X509_free(recip);
1053280304Sjkim    X509_free(signer);
1054280304Sjkim    EVP_PKEY_free(key);
1055280304Sjkim    CMS_ContentInfo_free(cms);
1056280304Sjkim    CMS_ContentInfo_free(rcms);
1057280304Sjkim    BIO_free(rctin);
1058280304Sjkim    BIO_free(in);
1059280304Sjkim    BIO_free(indata);
1060280304Sjkim    BIO_free_all(out);
1061280304Sjkim    if (passin)
1062280304Sjkim        OPENSSL_free(passin);
1063280304Sjkim    return (ret);
1064183234Ssimon}
1065183234Ssimon
1066183234Ssimonstatic int save_certs(char *signerfile, STACK_OF(X509) *signers)
1067280304Sjkim{
1068280304Sjkim    int i;
1069280304Sjkim    BIO *tmp;
1070280304Sjkim    if (!signerfile)
1071280304Sjkim        return 1;
1072280304Sjkim    tmp = BIO_new_file(signerfile, "w");
1073280304Sjkim    if (!tmp)
1074280304Sjkim        return 0;
1075280304Sjkim    for (i = 0; i < sk_X509_num(signers); i++)
1076280304Sjkim        PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
1077280304Sjkim    BIO_free(tmp);
1078280304Sjkim    return 1;
1079280304Sjkim}
1080183234Ssimon
1081183234Ssimon/* Minimal callback just to output policy info (if any) */
1082183234Ssimon
1083183234Ssimonstatic int cms_cb(int ok, X509_STORE_CTX *ctx)
1084280304Sjkim{
1085280304Sjkim    int error;
1086183234Ssimon
1087280304Sjkim    error = X509_STORE_CTX_get_error(ctx);
1088183234Ssimon
1089280304Sjkim    verify_err = error;
1090238405Sjkim
1091280304Sjkim    if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
1092280304Sjkim        && ((error != X509_V_OK) || (ok != 2)))
1093280304Sjkim        return ok;
1094183234Ssimon
1095280304Sjkim    policies_print(NULL, ctx);
1096183234Ssimon
1097280304Sjkim    return ok;
1098183234Ssimon
1099280304Sjkim}
1100183234Ssimon
1101183234Ssimonstatic void gnames_stack_print(BIO *out, STACK_OF(GENERAL_NAMES) *gns)
1102280304Sjkim{
1103280304Sjkim    STACK_OF(GENERAL_NAME) *gens;
1104280304Sjkim    GENERAL_NAME *gen;
1105280304Sjkim    int i, j;
1106280304Sjkim    for (i = 0; i < sk_GENERAL_NAMES_num(gns); i++) {
1107280304Sjkim        gens = sk_GENERAL_NAMES_value(gns, i);
1108280304Sjkim        for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) {
1109280304Sjkim            gen = sk_GENERAL_NAME_value(gens, j);
1110280304Sjkim            BIO_puts(out, "    ");
1111280304Sjkim            GENERAL_NAME_print(out, gen);
1112280304Sjkim            BIO_puts(out, "\n");
1113280304Sjkim        }
1114280304Sjkim    }
1115280304Sjkim    return;
1116280304Sjkim}
1117183234Ssimon
1118183234Ssimonstatic void receipt_request_print(BIO *out, CMS_ContentInfo *cms)
1119280304Sjkim{
1120280304Sjkim    STACK_OF(CMS_SignerInfo) *sis;
1121280304Sjkim    CMS_SignerInfo *si;
1122280304Sjkim    CMS_ReceiptRequest *rr;
1123280304Sjkim    int allorfirst;
1124280304Sjkim    STACK_OF(GENERAL_NAMES) *rto, *rlist;
1125280304Sjkim    ASN1_STRING *scid;
1126280304Sjkim    int i, rv;
1127280304Sjkim    sis = CMS_get0_SignerInfos(cms);
1128280304Sjkim    for (i = 0; i < sk_CMS_SignerInfo_num(sis); i++) {
1129280304Sjkim        si = sk_CMS_SignerInfo_value(sis, i);
1130280304Sjkim        rv = CMS_get1_ReceiptRequest(si, &rr);
1131280304Sjkim        BIO_printf(bio_err, "Signer %d:\n", i + 1);
1132280304Sjkim        if (rv == 0)
1133280304Sjkim            BIO_puts(bio_err, "  No Receipt Request\n");
1134280304Sjkim        else if (rv < 0) {
1135280304Sjkim            BIO_puts(bio_err, "  Receipt Request Parse Error\n");
1136280304Sjkim            ERR_print_errors(bio_err);
1137280304Sjkim        } else {
1138280304Sjkim            char *id;
1139280304Sjkim            int idlen;
1140280304Sjkim            CMS_ReceiptRequest_get0_values(rr, &scid, &allorfirst,
1141280304Sjkim                                           &rlist, &rto);
1142280304Sjkim            BIO_puts(out, "  Signed Content ID:\n");
1143280304Sjkim            idlen = ASN1_STRING_length(scid);
1144280304Sjkim            id = (char *)ASN1_STRING_data(scid);
1145280304Sjkim            BIO_dump_indent(out, id, idlen, 4);
1146280304Sjkim            BIO_puts(out, "  Receipts From");
1147280304Sjkim            if (rlist) {
1148280304Sjkim                BIO_puts(out, " List:\n");
1149280304Sjkim                gnames_stack_print(out, rlist);
1150280304Sjkim            } else if (allorfirst == 1)
1151280304Sjkim                BIO_puts(out, ": First Tier\n");
1152280304Sjkim            else if (allorfirst == 0)
1153280304Sjkim                BIO_puts(out, ": All\n");
1154280304Sjkim            else
1155280304Sjkim                BIO_printf(out, " Unknown (%d)\n", allorfirst);
1156280304Sjkim            BIO_puts(out, "  Receipts To:\n");
1157280304Sjkim            gnames_stack_print(out, rto);
1158280304Sjkim        }
1159280304Sjkim        if (rr)
1160280304Sjkim            CMS_ReceiptRequest_free(rr);
1161280304Sjkim    }
1162280304Sjkim}
1163183234Ssimon
1164238405Sjkimstatic STACK_OF(GENERAL_NAMES) *make_names_stack(STACK_OF(OPENSSL_STRING) *ns)
1165280304Sjkim{
1166280304Sjkim    int i;
1167280304Sjkim    STACK_OF(GENERAL_NAMES) *ret;
1168280304Sjkim    GENERAL_NAMES *gens = NULL;
1169280304Sjkim    GENERAL_NAME *gen = NULL;
1170280304Sjkim    ret = sk_GENERAL_NAMES_new_null();
1171280304Sjkim    if (!ret)
1172280304Sjkim        goto err;
1173280304Sjkim    for (i = 0; i < sk_OPENSSL_STRING_num(ns); i++) {
1174280304Sjkim        char *str = sk_OPENSSL_STRING_value(ns, i);
1175280304Sjkim        gen = a2i_GENERAL_NAME(NULL, NULL, NULL, GEN_EMAIL, str, 0);
1176280304Sjkim        if (!gen)
1177280304Sjkim            goto err;
1178280304Sjkim        gens = GENERAL_NAMES_new();
1179280304Sjkim        if (!gens)
1180280304Sjkim            goto err;
1181280304Sjkim        if (!sk_GENERAL_NAME_push(gens, gen))
1182280304Sjkim            goto err;
1183280304Sjkim        gen = NULL;
1184280304Sjkim        if (!sk_GENERAL_NAMES_push(ret, gens))
1185280304Sjkim            goto err;
1186280304Sjkim        gens = NULL;
1187280304Sjkim    }
1188183234Ssimon
1189280304Sjkim    return ret;
1190183234Ssimon
1191280304Sjkim err:
1192280304Sjkim    if (ret)
1193280304Sjkim        sk_GENERAL_NAMES_pop_free(ret, GENERAL_NAMES_free);
1194280304Sjkim    if (gens)
1195280304Sjkim        GENERAL_NAMES_free(gens);
1196280304Sjkim    if (gen)
1197280304Sjkim        GENERAL_NAME_free(gen);
1198280304Sjkim    return NULL;
1199280304Sjkim}
1200183234Ssimon
1201280304Sjkimstatic CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING)
1202280304Sjkim                                                *rr_to, int rr_allorfirst, STACK_OF(OPENSSL_STRING)
1203280304Sjkim                                                *rr_from)
1204280304Sjkim{
1205280304Sjkim    STACK_OF(GENERAL_NAMES) *rct_to, *rct_from;
1206280304Sjkim    CMS_ReceiptRequest *rr;
1207280304Sjkim    rct_to = make_names_stack(rr_to);
1208280304Sjkim    if (!rct_to)
1209280304Sjkim        goto err;
1210280304Sjkim    if (rr_from) {
1211280304Sjkim        rct_from = make_names_stack(rr_from);
1212280304Sjkim        if (!rct_from)
1213280304Sjkim            goto err;
1214280304Sjkim    } else
1215280304Sjkim        rct_from = NULL;
1216280304Sjkim    rr = CMS_ReceiptRequest_create0(NULL, -1, rr_allorfirst, rct_from,
1217280304Sjkim                                    rct_to);
1218280304Sjkim    return rr;
1219280304Sjkim err:
1220280304Sjkim    return NULL;
1221280304Sjkim}
1222183234Ssimon
1223183234Ssimon#endif
1224