[BACK]Return to cms.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / openssl

Annotation of src/usr.bin/openssl/cms.c, Revision 1.33

1.33    ! tb          1: /* $OpenBSD: cms.c,v 1.32 2023/03/05 13:08:22 tb Exp $ */
1.1       jsing       2: /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
                      3:  * project.
                      4:  */
                      5: /* ====================================================================
                      6:  * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  *
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  *
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in
                     17:  *    the documentation and/or other materials provided with the
                     18:  *    distribution.
                     19:  *
                     20:  * 3. All advertising materials mentioning features or use of this
                     21:  *    software must display the following acknowledgment:
                     22:  *    "This product includes software developed by the OpenSSL Project
                     23:  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
                     24:  *
                     25:  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
                     26:  *    endorse or promote products derived from this software without
                     27:  *    prior written permission. For written permission, please contact
                     28:  *    licensing@OpenSSL.org.
                     29:  *
                     30:  * 5. Products derived from this software may not be called "OpenSSL"
                     31:  *    nor may "OpenSSL" appear in their names without prior written
                     32:  *    permission of the OpenSSL Project.
                     33:  *
                     34:  * 6. Redistributions of any form whatsoever must retain the following
                     35:  *    acknowledgment:
                     36:  *    "This product includes software developed by the OpenSSL Project
                     37:  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
                     38:  *
                     39:  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
                     40:  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     41:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     42:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
                     43:  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     44:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     45:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     46:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     47:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     48:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     49:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
                     50:  * OF THE POSSIBILITY OF SUCH DAMAGE.
                     51:  * ====================================================================
                     52:  */
                     53:
                     54: /* CMS utility function */
                     55:
                     56: #include <stdio.h>
                     57: #include <string.h>
                     58:
                     59: #include "apps.h"
                     60:
                     61: #ifndef OPENSSL_NO_CMS
                     62:
                     63: #include <openssl/crypto.h>
                     64: #include <openssl/err.h>
                     65: #include <openssl/pem.h>
                     66: #include <openssl/x509_vfy.h>
                     67: #include <openssl/x509v3.h>
1.10      jsing      68:
                     69: #include <openssl/cms.h>
1.1       jsing      70:
1.12      jsing      71: static int save_certs(char *signerfile, STACK_OF(X509) *signers);
                     72: static int cms_cb(int ok, X509_STORE_CTX *ctx);
                     73: static void receipt_request_print(BIO *out, CMS_ContentInfo *cms);
                     74: static CMS_ReceiptRequest *make_receipt_request(
                     75:     STACK_OF(OPENSSL_STRING) *rr_to, int rr_allorfirst,
                     76:     STACK_OF(OPENSSL_STRING) *rr_from);
1.14      inoguchi   77: static int cms_set_pkey_param(EVP_PKEY_CTX *pctx,
                     78:     STACK_OF(OPENSSL_STRING) *param);
1.1       jsing      79:
                     80: #define SMIME_OP       0x10
                     81: #define SMIME_IP       0x20
                     82: #define SMIME_SIGNERS  0x40
                     83: #define SMIME_ENCRYPT          (1 | SMIME_OP)
                     84: #define SMIME_DECRYPT          (2 | SMIME_IP)
                     85: #define SMIME_SIGN             (3 | SMIME_OP | SMIME_SIGNERS)
                     86: #define SMIME_VERIFY           (4 | SMIME_IP)
                     87: #define SMIME_CMSOUT           (5 | SMIME_IP | SMIME_OP)
                     88: #define SMIME_RESIGN           (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
                     89: #define SMIME_DATAOUT          (7 | SMIME_IP)
                     90: #define SMIME_DATA_CREATE      (8 | SMIME_OP)
                     91: #define SMIME_DIGEST_VERIFY    (9 | SMIME_IP)
                     92: #define SMIME_DIGEST_CREATE    (10 | SMIME_OP)
                     93: #define SMIME_UNCOMPRESS       (11 | SMIME_IP)
                     94: #define SMIME_COMPRESS         (12 | SMIME_OP)
                     95: #define SMIME_ENCRYPTED_DECRYPT        (13 | SMIME_IP)
                     96: #define SMIME_ENCRYPTED_ENCRYPT        (14 | SMIME_OP)
                     97: #define SMIME_SIGN_RECEIPT     (15 | SMIME_IP | SMIME_OP)
                     98: #define SMIME_VERIFY_RECEIPT   (16 | SMIME_IP)
                     99:
                    100: int verify_err = 0;
                    101:
1.15      inoguchi  102: struct cms_key_param {
1.14      inoguchi  103:        int idx;
                    104:        STACK_OF(OPENSSL_STRING) *param;
1.15      inoguchi  105:        struct cms_key_param *next;
1.14      inoguchi  106: };
                    107:
1.19      inoguchi  108: static struct {
                    109:        char *CAfile;
                    110:        char *CApath;
                    111:        X509 *cert;
                    112:        char *certfile;
                    113:        char *certsoutfile;
                    114:        const EVP_CIPHER *cipher;
                    115:        char *contfile;
                    116:        ASN1_OBJECT *econtent_type;
                    117:        STACK_OF(X509) *encerts;
                    118:        int flags;
                    119:        char *from;
                    120:        char *infile;
                    121:        int informat;
                    122:        struct cms_key_param *key_first;
                    123:        struct cms_key_param *key_param;
                    124:        char *keyfile;
                    125:        int keyform;
                    126:        int noout;
                    127:        int operation;
                    128:        char *outfile;
                    129:        int outformat;
                    130:        char *passargin;
                    131:        int print;
                    132:        unsigned char *pwri_pass;
                    133:        int rr_allorfirst;
                    134:        STACK_OF(OPENSSL_STRING) *rr_from;
                    135:        int rr_print;
                    136:        STACK_OF(OPENSSL_STRING) *rr_to;
                    137:        char *rctfile;
                    138:        int rctformat;
                    139:        char *recipfile;
                    140:        unsigned char *secret_key;
                    141:        unsigned char *secret_keyid;
                    142:        size_t secret_keyidlen;
                    143:        size_t secret_keylen;
                    144:        const EVP_MD *sign_md;
                    145:        char *signerfile;
                    146:        STACK_OF(OPENSSL_STRING) *skkeys;
                    147:        STACK_OF(OPENSSL_STRING) *sksigners;
                    148:        char *subject;
                    149:        char *to;
                    150:        int verify_retcode;
                    151:        X509_VERIFY_PARAM *vpm;
1.33    ! tb        152: } cfg;
1.19      inoguchi  153:
                    154: static const EVP_CIPHER *
                    155: get_cipher_by_name(char *name)
                    156: {
                    157:        if (name == NULL || strcmp(name, "") == 0)
                    158:                return (NULL);
                    159: #ifndef OPENSSL_NO_AES
                    160:        else if (strcmp(name, "aes128") == 0)
                    161:                return EVP_aes_128_cbc();
                    162:        else if (strcmp(name, "aes192") == 0)
                    163:                return EVP_aes_192_cbc();
                    164:        else if (strcmp(name, "aes256") == 0)
                    165:                return EVP_aes_256_cbc();
                    166: #endif
                    167: #ifndef OPENSSL_NO_CAMELLIA
                    168:        else if (strcmp(name, "camellia128") == 0)
                    169:                return EVP_camellia_128_cbc();
                    170:        else if (strcmp(name, "camellia192") == 0)
                    171:                return EVP_camellia_192_cbc();
                    172:        else if (strcmp(name, "camellia256") == 0)
                    173:                return EVP_camellia_256_cbc();
                    174: #endif
                    175: #ifndef OPENSSL_NO_DES
                    176:        else if (strcmp(name, "des") == 0)
                    177:                return EVP_des_cbc();
                    178:        else if (strcmp(name, "des3") == 0)
                    179:                return EVP_des_ede3_cbc();
                    180: #endif
                    181: #ifndef OPENSSL_NO_RC2
                    182:        else if (!strcmp(name, "rc2-40"))
                    183:                return EVP_rc2_40_cbc();
                    184:        else if (!strcmp(name, "rc2-64"))
                    185:                return EVP_rc2_64_cbc();
                    186:        else if (!strcmp(name, "rc2-128"))
                    187:                return EVP_rc2_cbc();
                    188: #endif
                    189:        else
                    190:                return (NULL);
                    191: }
                    192:
                    193: static int
                    194: cms_opt_cipher(int argc, char **argv, int *argsused)
                    195: {
                    196:        char *name = argv[0];
                    197:
                    198:        if (*name++ != '-')
                    199:                return (1);
                    200:
1.33    ! tb        201:        if ((cfg.cipher = get_cipher_by_name(name)) == NULL)
        !           202:                if ((cfg.cipher = EVP_get_cipherbyname(name)) == NULL)
1.19      inoguchi  203:                        return (1);
                    204:
                    205:        *argsused = 1;
                    206:        return (0);
                    207: }
                    208:
                    209: static int
                    210: cms_opt_econtent_type(char *arg)
                    211: {
1.33    ! tb        212:        ASN1_OBJECT_free(cfg.econtent_type);
1.27      inoguchi  213:
1.33    ! tb        214:        if ((cfg.econtent_type = OBJ_txt2obj(arg, 0)) == NULL) {
1.19      inoguchi  215:                BIO_printf(bio_err, "Invalid OID %s\n", arg);
                    216:                return (1);
                    217:        }
                    218:        return (0);
                    219: }
                    220:
                    221: static int
                    222: cms_opt_inkey(char *arg)
                    223: {
1.33    ! tb        224:        if (cfg.keyfile == NULL) {
        !           225:                cfg.keyfile = arg;
1.20      inoguchi  226:                return (0);
                    227:        }
1.32      tb        228:
1.33    ! tb        229:        if (cfg.signerfile == NULL) {
1.20      inoguchi  230:                BIO_puts(bio_err, "Illegal -inkey without -signer\n");
                    231:                return (1);
                    232:        }
                    233:
1.33    ! tb        234:        if (cfg.sksigners == NULL)
        !           235:                cfg.sksigners = sk_OPENSSL_STRING_new_null();
        !           236:        if (cfg.sksigners == NULL)
1.20      inoguchi  237:                return (1);
1.33    ! tb        238:        if (!sk_OPENSSL_STRING_push(cfg.sksigners, cfg.signerfile))
1.20      inoguchi  239:                return (1);
1.19      inoguchi  240:
1.33    ! tb        241:        cfg.signerfile = NULL;
1.19      inoguchi  242:
1.33    ! tb        243:        if (cfg.skkeys == NULL)
        !           244:                cfg.skkeys = sk_OPENSSL_STRING_new_null();
        !           245:        if (cfg.skkeys == NULL)
1.20      inoguchi  246:                return (1);
1.33    ! tb        247:        if (!sk_OPENSSL_STRING_push(cfg.skkeys, cfg.keyfile))
1.20      inoguchi  248:                return (1);
1.19      inoguchi  249:
1.33    ! tb        250:        cfg.keyfile = arg;
1.19      inoguchi  251:        return (0);
                    252: }
                    253:
                    254: static int
                    255: cms_opt_keyopt(char *arg)
                    256: {
                    257:        int keyidx = -1;
                    258:
1.33    ! tb        259:        if (cfg.operation == SMIME_ENCRYPT) {
        !           260:                if (cfg.encerts != NULL)
        !           261:                        keyidx += sk_X509_num(cfg.encerts);
1.19      inoguchi  262:        } else {
1.33    ! tb        263:                if (cfg.keyfile != NULL || cfg.signerfile != NULL)
1.19      inoguchi  264:                        keyidx++;
1.33    ! tb        265:                if (cfg.skkeys != NULL)
        !           266:                        keyidx += sk_OPENSSL_STRING_num(cfg.skkeys);
1.19      inoguchi  267:        }
                    268:
                    269:        if (keyidx < 0) {
                    270:                BIO_printf(bio_err, "No key specified\n");
                    271:                return (1);
                    272:        }
                    273:
1.33    ! tb        274:        if (cfg.key_param == NULL ||
        !           275:            cfg.key_param->idx != keyidx) {
1.19      inoguchi  276:                struct cms_key_param *nparam;
                    277:
1.21      inoguchi  278:                if ((nparam = calloc(1, sizeof(struct cms_key_param))) == NULL)
1.19      inoguchi  279:                        return (1);
                    280:
                    281:                nparam->idx = keyidx;
                    282:                if ((nparam->param = sk_OPENSSL_STRING_new_null()) == NULL) {
                    283:                        free(nparam);
                    284:                        return (1);
                    285:                }
                    286:
                    287:                nparam->next = NULL;
1.33    ! tb        288:                if (cfg.key_first == NULL)
        !           289:                        cfg.key_first = nparam;
1.19      inoguchi  290:                else
1.33    ! tb        291:                        cfg.key_param->next = nparam;
1.19      inoguchi  292:
1.33    ! tb        293:                cfg.key_param = nparam;
1.19      inoguchi  294:        }
                    295:
1.33    ! tb        296:        if (!sk_OPENSSL_STRING_push(cfg.key_param->param, arg))
1.19      inoguchi  297:                return (1);
                    298:
                    299:        return (0);
                    300: }
                    301:
                    302: static int
                    303: cms_opt_md(char *arg)
                    304: {
1.33    ! tb        305:        if ((cfg.sign_md = EVP_get_digestbyname(arg)) == NULL) {
1.19      inoguchi  306:                BIO_printf(bio_err, "Unknown digest %s\n", arg);
                    307:                return (1);
                    308:        }
                    309:        return (0);
                    310: }
                    311:
                    312: static int
                    313: cms_opt_print(void)
                    314: {
1.33    ! tb        315:        cfg.noout = 1;
        !           316:        cfg.print = 1;
1.19      inoguchi  317:        return (0);
                    318: }
                    319:
                    320: static int
                    321: cms_opt_pwri_pass(char *arg)
                    322: {
1.33    ! tb        323:        cfg.pwri_pass = (unsigned char *)arg;
1.19      inoguchi  324:        return (0);
                    325: }
                    326:
                    327: static int
                    328: cms_opt_recip(char *arg)
                    329: {
1.33    ! tb        330:        if (cfg.operation == SMIME_ENCRYPT) {
        !           331:                if (cfg.encerts == NULL) {
        !           332:                        if ((cfg.encerts = sk_X509_new_null()) == NULL)
1.19      inoguchi  333:                                return (1);
                    334:                }
                    335:
1.33    ! tb        336:                cfg.cert = load_cert(bio_err, arg, FORMAT_PEM,
1.19      inoguchi  337:                    NULL, "recipient certificate file");
1.33    ! tb        338:                if (cfg.cert == NULL)
1.19      inoguchi  339:                        return (1);
                    340:
1.33    ! tb        341:                if (!sk_X509_push(cfg.encerts, cfg.cert))
1.19      inoguchi  342:                        return (1);
                    343:
1.33    ! tb        344:                cfg.cert = NULL;
1.19      inoguchi  345:        } else {
1.33    ! tb        346:                cfg.recipfile = arg;
1.19      inoguchi  347:        }
                    348:        return (0);
                    349: }
                    350:
                    351: static int
                    352: cms_opt_receipt_request_from(char *arg)
                    353: {
1.33    ! tb        354:        if (cfg.rr_from == NULL)
        !           355:                cfg.rr_from = sk_OPENSSL_STRING_new_null();
        !           356:        if (cfg.rr_from == NULL)
1.19      inoguchi  357:                return (1);
1.33    ! tb        358:        if (!sk_OPENSSL_STRING_push(cfg.rr_from, arg))
1.19      inoguchi  359:                return (1);
                    360:
                    361:        return (0);
                    362: }
                    363:
                    364: static int
                    365: cms_opt_receipt_request_to(char *arg)
                    366: {
1.33    ! tb        367:        if (cfg.rr_to == NULL)
        !           368:                cfg.rr_to = sk_OPENSSL_STRING_new_null();
        !           369:        if (cfg.rr_to == NULL)
1.19      inoguchi  370:                return (1);
1.33    ! tb        371:        if (!sk_OPENSSL_STRING_push(cfg.rr_to, arg))
1.19      inoguchi  372:                return (1);
                    373:
                    374:        return (0);
                    375: }
                    376:
                    377: static int
                    378: cms_opt_secretkey(char *arg)
                    379: {
                    380:        long ltmp;
                    381:
1.33    ! tb        382:        free(cfg.secret_key);
1.27      inoguchi  383:
1.33    ! tb        384:        if ((cfg.secret_key = string_to_hex(arg, &ltmp)) == NULL) {
1.19      inoguchi  385:                BIO_printf(bio_err, "Invalid key %s\n", arg);
                    386:                return (1);
                    387:        }
1.33    ! tb        388:        cfg.secret_keylen = (size_t)ltmp;
1.19      inoguchi  389:        return (0);
                    390: }
                    391:
                    392: static int
                    393: cms_opt_secretkeyid(char *arg)
                    394: {
                    395:        long ltmp;
1.27      inoguchi  396:
1.33    ! tb        397:        free(cfg.secret_keyid);
1.19      inoguchi  398:
1.33    ! tb        399:        if ((cfg.secret_keyid = string_to_hex(arg, &ltmp)) == NULL) {
1.19      inoguchi  400:                BIO_printf(bio_err, "Invalid id %s\n", arg);
                    401:                return (1);
                    402:        }
1.33    ! tb        403:        cfg.secret_keyidlen = (size_t)ltmp;
1.19      inoguchi  404:        return (0);
                    405: }
                    406:
                    407: static int
                    408: cms_opt_signer(char *arg)
                    409: {
1.33    ! tb        410:        if (cfg.signerfile == NULL) {
        !           411:                cfg.signerfile = arg;
1.20      inoguchi  412:                return (0);
                    413:        }
                    414:
1.33    ! tb        415:        if (cfg.sksigners == NULL)
        !           416:                cfg.sksigners = sk_OPENSSL_STRING_new_null();
        !           417:        if (cfg.sksigners == NULL)
1.20      inoguchi  418:                return (1);
1.33    ! tb        419:        if (!sk_OPENSSL_STRING_push(cfg.sksigners, cfg.signerfile))
1.20      inoguchi  420:                return (1);
                    421:
1.33    ! tb        422:        if (cfg.keyfile == NULL)
        !           423:                cfg.keyfile = cfg.signerfile;
1.19      inoguchi  424:
1.33    ! tb        425:        if (cfg.skkeys == NULL)
        !           426:                cfg.skkeys = sk_OPENSSL_STRING_new_null();
        !           427:        if (cfg.skkeys == NULL)
1.20      inoguchi  428:                return (1);
1.33    ! tb        429:        if (!sk_OPENSSL_STRING_push(cfg.skkeys, cfg.keyfile))
1.20      inoguchi  430:                return (1);
1.19      inoguchi  431:
1.33    ! tb        432:        cfg.keyfile = NULL;
1.19      inoguchi  433:
1.33    ! tb        434:        cfg.signerfile = arg;
1.19      inoguchi  435:        return (0);
                    436: }
                    437:
                    438: static int
                    439: cms_opt_verify_param(int argc, char **argv, int *argsused)
                    440: {
                    441:        int oargc = argc;
                    442:        int badarg = 0;
                    443:
1.33    ! tb        444:        if (!args_verify(&argv, &argc, &badarg, bio_err, &cfg.vpm))
1.19      inoguchi  445:                return (1);
                    446:        if (badarg)
                    447:                return (1);
                    448:
                    449:        *argsused = oargc - argc;
                    450:
                    451:        return (0);
                    452: }
                    453:
                    454: static int
                    455: cms_opt_verify_receipt(char *arg)
                    456: {
1.33    ! tb        457:        cfg.operation = SMIME_VERIFY_RECEIPT;
        !           458:        cfg.rctfile = arg;
1.19      inoguchi  459:        return (0);
                    460: }
                    461:
                    462: static const struct option cms_options[] = {
                    463: #ifndef OPENSSL_NO_AES
                    464:        {
                    465:                .name = "aes128",
                    466:                .desc = "Encrypt PEM output with CBC AES",
                    467:                .type = OPTION_ARGV_FUNC,
                    468:                .opt.argvfunc = cms_opt_cipher,
                    469:        },
                    470:        {
                    471:                .name = "aes192",
                    472:                .desc = "Encrypt PEM output with CBC AES",
                    473:                .type = OPTION_ARGV_FUNC,
                    474:                .opt.argvfunc = cms_opt_cipher,
                    475:        },
                    476:        {
                    477:                .name = "aes256",
                    478:                .desc = "Encrypt PEM output with CBC AES",
                    479:                .type = OPTION_ARGV_FUNC,
                    480:                .opt.argvfunc = cms_opt_cipher,
                    481:        },
                    482: #endif
                    483: #ifndef OPENSSL_NO_CAMELLIA
                    484:        {
                    485:                .name = "camellia128",
                    486:                .desc = "Encrypt PEM output with CBC Camellia",
                    487:                .type = OPTION_ARGV_FUNC,
                    488:                .opt.argvfunc = cms_opt_cipher,
                    489:        },
                    490:        {
                    491:                .name = "camellia192",
                    492:                .desc = "Encrypt PEM output with CBC Camellia",
                    493:                .type = OPTION_ARGV_FUNC,
                    494:                .opt.argvfunc = cms_opt_cipher,
                    495:        },
                    496:        {
                    497:                .name = "camellia256",
                    498:                .desc = "Encrypt PEM output with CBC Camellia",
                    499:                .type = OPTION_ARGV_FUNC,
                    500:                .opt.argvfunc = cms_opt_cipher,
                    501:        },
                    502: #endif
                    503: #ifndef OPENSSL_NO_DES
                    504:        {
                    505:                .name = "des",
                    506:                .desc = "Encrypt with DES",
                    507:                .type = OPTION_ARGV_FUNC,
                    508:                .opt.argvfunc = cms_opt_cipher,
                    509:        },
                    510:        {
                    511:                .name = "des3",
1.28      inoguchi  512:                .desc = "Encrypt with triple DES (default)",
1.19      inoguchi  513:                .type = OPTION_ARGV_FUNC,
                    514:                .opt.argvfunc = cms_opt_cipher,
                    515:        },
                    516: #endif
                    517: #ifndef OPENSSL_NO_RC2
                    518:        {
                    519:                .name = "rc2-40",
1.28      inoguchi  520:                .desc = "Encrypt with RC2-40",
1.19      inoguchi  521:                .type = OPTION_ARGV_FUNC,
                    522:                .opt.argvfunc = cms_opt_cipher,
                    523:        },
                    524:        {
                    525:                .name = "rc2-64",
                    526:                .desc = "Encrypt with RC2-64",
                    527:                .type = OPTION_ARGV_FUNC,
                    528:                .opt.argvfunc = cms_opt_cipher,
                    529:        },
                    530:        {
                    531:                .name = "rc2-128",
                    532:                .desc = "Encrypt with RC2-128",
                    533:                .type = OPTION_ARGV_FUNC,
                    534:                .opt.argvfunc = cms_opt_cipher,
                    535:        },
                    536: #endif
                    537:        {
                    538:                .name = "CAfile",
                    539:                .argname = "file",
                    540:                .desc = "Certificate Authority file",
                    541:                .type = OPTION_ARG,
1.33    ! tb        542:                .opt.arg = &cfg.CAfile,
1.19      inoguchi  543:        },
                    544:        {
                    545:                .name = "CApath",
                    546:                .argname = "path",
                    547:                .desc = "Certificate Authority path",
                    548:                .type = OPTION_ARG,
1.33    ! tb        549:                .opt.arg = &cfg.CApath,
1.19      inoguchi  550:        },
                    551:        {
                    552:                .name = "binary",
                    553:                .desc = "Do not translate message to text",
                    554:                .type = OPTION_VALUE_OR,
1.33    ! tb        555:                .opt.value = &cfg.flags,
1.19      inoguchi  556:                .value = CMS_BINARY,
                    557:        },
                    558:        {
                    559:                .name = "certfile",
                    560:                .argname = "file",
                    561:                .desc = "Other certificates file",
                    562:                .type = OPTION_ARG,
1.33    ! tb        563:                .opt.arg = &cfg.certfile,
1.19      inoguchi  564:        },
                    565:        {
                    566:                .name = "certsout",
                    567:                .argname = "file",
                    568:                .desc = "Certificate output file",
                    569:                .type = OPTION_ARG,
1.33    ! tb        570:                .opt.arg = &cfg.certsoutfile,
1.19      inoguchi  571:        },
                    572:        {
                    573:                .name = "cmsout",
                    574:                .desc = "Output CMS structure",
                    575:                .type = OPTION_VALUE,
1.33    ! tb        576:                .opt.value = &cfg.operation,
1.19      inoguchi  577:                .value = SMIME_CMSOUT,
                    578:        },
                    579:        {
                    580:                .name = "compress",
                    581:                .desc = "Create CMS CompressedData type",
                    582:                .type = OPTION_VALUE,
1.33    ! tb        583:                .opt.value = &cfg.operation,
1.19      inoguchi  584:                .value = SMIME_COMPRESS,
                    585:        },
                    586:        {
                    587:                .name = "content",
                    588:                .argname = "file",
                    589:                .desc = "Supply or override content for detached signature",
                    590:                .type = OPTION_ARG,
1.33    ! tb        591:                .opt.arg = &cfg.contfile,
1.19      inoguchi  592:        },
                    593:        {
                    594:                .name = "crlfeol",
                    595:                .desc = "Use CRLF as EOL termination instead of CR only",
                    596:                .type = OPTION_VALUE_OR,
1.33    ! tb        597:                .opt.value = &cfg.flags,
1.19      inoguchi  598:                .value = CMS_CRLFEOL,
                    599:        },
                    600:        {
                    601:                .name = "data_create",
                    602:                .desc = "Create CMS Data type",
                    603:                .type = OPTION_VALUE,
1.33    ! tb        604:                .opt.value = &cfg.operation,
1.19      inoguchi  605:                .value = SMIME_DATA_CREATE,
                    606:        },
                    607:        {
                    608:                .name = "data_out",
                    609:                .desc = "Output content from the input CMS Data type",
                    610:                .type = OPTION_VALUE,
1.33    ! tb        611:                .opt.value = &cfg.operation,
1.19      inoguchi  612:                .value = SMIME_DATAOUT,
                    613:        },
                    614:        {
                    615:                .name = "debug_decrypt",
                    616:                .desc = "Set the CMS_DEBUG_DECRYPT flag when decrypting",
                    617:                .type = OPTION_VALUE_OR,
1.33    ! tb        618:                .opt.value = &cfg.flags,
1.19      inoguchi  619:                .value = CMS_DEBUG_DECRYPT,
                    620:        },
                    621:        {
                    622:                .name = "decrypt",
                    623:                .desc = "Decrypt encrypted message",
                    624:                .type = OPTION_VALUE,
1.33    ! tb        625:                .opt.value = &cfg.operation,
1.19      inoguchi  626:                .value = SMIME_DECRYPT,
                    627:        },
                    628:        {
                    629:                .name = "digest_create",
                    630:                .desc = "Create CMS DigestedData type",
                    631:                .type = OPTION_VALUE,
1.33    ! tb        632:                .opt.value = &cfg.operation,
1.19      inoguchi  633:                .value = SMIME_DIGEST_CREATE,
                    634:        },
                    635:        {
                    636:                .name = "digest_verify",
                    637:                .desc = "Verify CMS DigestedData type and output the content",
                    638:                .type = OPTION_VALUE,
1.33    ! tb        639:                .opt.value = &cfg.operation,
1.19      inoguchi  640:                .value = SMIME_DIGEST_VERIFY,
                    641:        },
                    642:        {
                    643:                .name = "econtent_type",
                    644:                .argname = "type",
                    645:                .desc = "Set the encapsulated content type",
                    646:                .type = OPTION_ARG_FUNC,
                    647:                .opt.argfunc = cms_opt_econtent_type,
                    648:        },
                    649:        {
                    650:                .name = "encrypt",
                    651:                .desc = "Encrypt message",
                    652:                .type = OPTION_VALUE,
1.33    ! tb        653:                .opt.value = &cfg.operation,
1.19      inoguchi  654:                .value = SMIME_ENCRYPT,
                    655:        },
                    656:        {
                    657:                .name = "EncryptedData_decrypt",
                    658:                .desc = "Decrypt CMS EncryptedData",
                    659:                .type = OPTION_VALUE,
1.33    ! tb        660:                .opt.value = &cfg.operation,
1.19      inoguchi  661:                .value = SMIME_ENCRYPTED_DECRYPT,
                    662:        },
                    663:        {
                    664:                .name = "EncryptedData_encrypt",
                    665:                .desc = "Encrypt content using supplied symmetric key and algorithm",
                    666:                .type = OPTION_VALUE,
1.33    ! tb        667:                .opt.value = &cfg.operation,
1.19      inoguchi  668:                .value = SMIME_ENCRYPTED_ENCRYPT,
                    669:        },
                    670:        {
                    671:                .name = "from",
                    672:                .argname = "addr",
                    673:                .desc = "From address",
                    674:                .type = OPTION_ARG,
1.33    ! tb        675:                .opt.arg = &cfg.from,
1.19      inoguchi  676:        },
                    677:        {
                    678:                .name = "in",
                    679:                .argname = "file",
                    680:                .desc = "Input file",
                    681:                .type = OPTION_ARG,
1.33    ! tb        682:                .opt.arg = &cfg.infile,
1.19      inoguchi  683:        },
                    684:        {
                    685:                .name = "indef",
                    686:                .desc = "Same as -stream",
                    687:                .type = OPTION_VALUE_OR,
1.33    ! tb        688:                .opt.value = &cfg.flags,
1.19      inoguchi  689:                .value = CMS_STREAM,
                    690:        },
                    691:        {
                    692:                .name = "inform",
                    693:                .argname = "fmt",
                    694:                .desc = "Input format (DER, PEM or SMIME (default))",
                    695:                .type = OPTION_ARG_FORMAT,
1.33    ! tb        696:                .opt.value = &cfg.informat,
1.19      inoguchi  697:        },
                    698:        {
                    699:                .name = "inkey",
                    700:                .argname = "file",
                    701:                .desc = "Input key file",
                    702:                .type = OPTION_ARG_FUNC,
                    703:                .opt.argfunc = cms_opt_inkey,
                    704:        },
                    705:        {
                    706:                .name = "keyform",
                    707:                .argname = "fmt",
                    708:                .desc = "Input key format (DER or PEM (default))",
                    709:                .type = OPTION_ARG_FORMAT,
1.33    ! tb        710:                .opt.value = &cfg.keyform,
1.19      inoguchi  711:        },
                    712:        {
                    713:                .name = "keyid",
                    714:                .desc = "Use subject key identifier",
                    715:                .type = OPTION_VALUE_OR,
1.33    ! tb        716:                .opt.value = &cfg.flags,
1.19      inoguchi  717:                .value = CMS_USE_KEYID,
                    718:        },
                    719:        {
                    720:                .name = "keyopt",
                    721:                .argname = "nm:v",
                    722:                .desc = "Set public key parameters",
                    723:                .type = OPTION_ARG_FUNC,
                    724:                .opt.argfunc = cms_opt_keyopt,
                    725:        },
                    726:        {
                    727:                .name = "md",
                    728:                .argname = "digest",
                    729:                .desc = "Digest to use when signing or resigning",
                    730:                .type = OPTION_ARG_FUNC,
                    731:                .opt.argfunc = cms_opt_md,
                    732:        },
                    733:        {
                    734:                .name = "no_attr_verify",
                    735:                .desc = "Do not verify the signer's attribute of a signature",
                    736:                .type = OPTION_VALUE_OR,
1.33    ! tb        737:                .opt.value = &cfg.flags,
1.19      inoguchi  738:                .value = CMS_NO_ATTR_VERIFY,
                    739:        },
                    740:        {
                    741:                .name = "no_content_verify",
                    742:                .desc = "Do not verify the content of a signed message",
                    743:                .type = OPTION_VALUE_OR,
1.33    ! tb        744:                .opt.value = &cfg.flags,
1.19      inoguchi  745:                .value = CMS_NO_CONTENT_VERIFY,
                    746:        },
                    747:        {
                    748:                .name = "no_signer_cert_verify",
                    749:                .desc = "Do not verify the signer's certificate",
                    750:                .type = OPTION_VALUE_OR,
1.33    ! tb        751:                .opt.value = &cfg.flags,
1.19      inoguchi  752:                .value = CMS_NO_SIGNER_CERT_VERIFY,
                    753:        },
                    754:        {
                    755:                .name = "noattr",
                    756:                .desc = "Do not include any signed attributes",
                    757:                .type = OPTION_VALUE_OR,
1.33    ! tb        758:                .opt.value = &cfg.flags,
1.19      inoguchi  759:                .value = CMS_NOATTR,
                    760:        },
                    761:        {
                    762:                .name = "nocerts",
                    763:                .desc = "Do not include signer's certificate when signing",
                    764:                .type = OPTION_VALUE_OR,
1.33    ! tb        765:                .opt.value = &cfg.flags,
1.19      inoguchi  766:                .value = CMS_NOCERTS,
                    767:        },
                    768:        {
                    769:                .name = "nodetach",
                    770:                .desc = "Use opaque signing",
                    771:                .type = OPTION_VALUE_AND,
1.33    ! tb        772:                .opt.value = &cfg.flags,
1.19      inoguchi  773:                .value = ~CMS_DETACHED,
                    774:        },
                    775:        {
                    776:                .name = "noindef",
                    777:                .desc = "Disable CMS streaming",
                    778:                .type = OPTION_VALUE_AND,
1.33    ! tb        779:                .opt.value = &cfg.flags,
1.19      inoguchi  780:                .value = ~CMS_STREAM,
                    781:        },
                    782:        {
                    783:                .name = "nointern",
                    784:                .desc = "Do not search certificates in message for signer",
                    785:                .type = OPTION_VALUE_OR,
1.33    ! tb        786:                .opt.value = &cfg.flags,
1.19      inoguchi  787:                .value = CMS_NOINTERN,
                    788:        },
                    789:        {
                    790:                .name = "nooldmime",
                    791:                .desc = "Output old S/MIME content type",
                    792:                .type = OPTION_VALUE_OR,
1.33    ! tb        793:                .opt.value = &cfg.flags,
1.19      inoguchi  794:                .value = CMS_NOOLDMIMETYPE,
                    795:        },
                    796:        {
                    797:                .name = "noout",
                    798:                .desc = "Do not output the parsed CMS structure",
                    799:                .type = OPTION_FLAG,
1.33    ! tb        800:                .opt.flag = &cfg.noout,
1.19      inoguchi  801:        },
                    802:        {
                    803:                .name = "nosigs",
                    804:                .desc = "Do not verify message signature",
                    805:                .type = OPTION_VALUE_OR,
1.33    ! tb        806:                .opt.value = &cfg.flags,
1.19      inoguchi  807:                .value = CMS_NOSIGS,
                    808:        },
                    809:        {
                    810:                .name = "nosmimecap",
                    811:                .desc = "Omit the SMIMECapabilities attribute",
                    812:                .type = OPTION_VALUE_OR,
1.33    ! tb        813:                .opt.value = &cfg.flags,
1.19      inoguchi  814:                .value = CMS_NOSMIMECAP,
                    815:        },
                    816:        {
                    817:                .name = "noverify",
                    818:                .desc = "Do not verify signer's certificate",
                    819:                .type = OPTION_VALUE_OR,
1.33    ! tb        820:                .opt.value = &cfg.flags,
1.19      inoguchi  821:                .value = CMS_NO_SIGNER_CERT_VERIFY,
                    822:        },
                    823:        {
                    824:                .name = "out",
                    825:                .argname = "file",
                    826:                .desc = "Output file",
                    827:                .type = OPTION_ARG,
1.33    ! tb        828:                .opt.arg = &cfg.outfile,
1.19      inoguchi  829:        },
                    830:        {
                    831:                .name = "outform",
                    832:                .argname = "fmt",
                    833:                .desc = "Output format (DER, PEM or SMIME (default))",
                    834:                .type = OPTION_ARG_FORMAT,
1.33    ! tb        835:                .opt.value = &cfg.outformat,
1.19      inoguchi  836:        },
                    837:        {
                    838:                .name = "passin",
                    839:                .argname = "src",
                    840:                .desc = "Private key password source",
                    841:                .type = OPTION_ARG,
1.33    ! tb        842:                .opt.arg = &cfg.passargin,
1.19      inoguchi  843:        },
                    844:        {
                    845:                .name = "print",
                    846:                .desc = "Print out all fields of the CMS structure for the -cmsout",
                    847:                .type = OPTION_FUNC,
                    848:                .opt.func = cms_opt_print,
                    849:        },
                    850:        {
                    851:                .name = "pwri_password",
                    852:                .argname = "arg",
                    853:                .desc = "Specify PasswordRecipientInfo (PWRI) password to use",
                    854:                .type = OPTION_ARG_FUNC,
                    855:                .opt.argfunc = cms_opt_pwri_pass,
                    856:        },
                    857:        {
                    858:                .name = "rctform",
                    859:                .argname = "fmt",
                    860:                .desc = "Receipt file format (DER, PEM or SMIME (default))",
                    861:                .type = OPTION_ARG_FORMAT,
1.33    ! tb        862:                .opt.value = &cfg.rctformat,
1.19      inoguchi  863:        },
                    864:        {
                    865:                .name = "receipt_request_all",
                    866:                .desc = "Indicate requests should be provided by all recipients",
                    867:                .type = OPTION_VALUE,
1.33    ! tb        868:                .opt.value = &cfg.rr_allorfirst,
1.19      inoguchi  869:                .value = 0,
                    870:        },
                    871:        {
                    872:                .name = "receipt_request_first",
                    873:                .desc = "Indicate requests should be provided by first tier recipient",
                    874:                .type = OPTION_VALUE,
1.33    ! tb        875:                .opt.value = &cfg.rr_allorfirst,
1.19      inoguchi  876:                .value = 1,
                    877:        },
                    878:        {
                    879:                .name = "receipt_request_from",
                    880:                .argname = "addr",
                    881:                .desc = "Add explicit email address where receipts should be supplied",
                    882:                .type = OPTION_ARG_FUNC,
                    883:                .opt.argfunc = cms_opt_receipt_request_from,
                    884:        },
                    885:        {
                    886:                .name = "receipt_request_print",
                    887:                .desc = "Print out the contents of any signed receipt requests",
                    888:                .type = OPTION_FLAG,
1.33    ! tb        889:                .opt.flag = &cfg.rr_print,
1.19      inoguchi  890:        },
                    891:        {
                    892:                .name = "receipt_request_to",
                    893:                .argname = "addr",
                    894:                .desc = "Add explicit email address where receipts should be sent to",
                    895:                .type = OPTION_ARG_FUNC,
                    896:                .opt.argfunc = cms_opt_receipt_request_to,
                    897:        },
                    898:        {
                    899:                .name = "recip",
                    900:                .argname = "file",
                    901:                .desc = "Recipient certificate file for decryption",
                    902:                .type = OPTION_ARG_FUNC,
                    903:                .opt.argfunc = cms_opt_recip,
                    904:        },
                    905:        {
                    906:                .name = "resign",
                    907:                .desc = "Resign a signed message",
                    908:                .type = OPTION_VALUE,
1.33    ! tb        909:                .opt.value = &cfg.operation,
1.19      inoguchi  910:                .value = SMIME_RESIGN,
                    911:        },
                    912:        {
                    913:                .name = "secretkey",
                    914:                .argname = "key",
                    915:                .desc = "Specify symmetric key to use",
                    916:                .type = OPTION_ARG_FUNC,
                    917:                .opt.argfunc = cms_opt_secretkey,
                    918:        },
                    919:        {
                    920:                .name = "secretkeyid",
                    921:                .argname = "id",
                    922:                .desc = "The key identifier for the supplied symmetric key",
                    923:                .type = OPTION_ARG_FUNC,
                    924:                .opt.argfunc = cms_opt_secretkeyid,
                    925:        },
                    926:        {
                    927:                .name = "sign",
                    928:                .desc = "Sign message",
                    929:                .type = OPTION_VALUE,
1.33    ! tb        930:                .opt.value = &cfg.operation,
1.19      inoguchi  931:                .value = SMIME_SIGN,
                    932:        },
                    933:        {
                    934:                .name = "sign_receipt",
                    935:                .desc = "Generate a signed receipt for the message",
                    936:                .type = OPTION_VALUE,
1.33    ! tb        937:                .opt.value = &cfg.operation,
1.19      inoguchi  938:                .value = SMIME_SIGN_RECEIPT,
                    939:        },
                    940:        {
                    941:                .name = "signer",
                    942:                .argname = "file",
                    943:                .desc = "Signer certificate file",
                    944:                .type = OPTION_ARG_FUNC,
                    945:                .opt.argfunc = cms_opt_signer,
                    946:        },
                    947:        {
                    948:                .name = "stream",
                    949:                .desc = "Enable CMS streaming",
                    950:                .type = OPTION_VALUE_OR,
1.33    ! tb        951:                .opt.value = &cfg.flags,
1.19      inoguchi  952:                .value = CMS_STREAM,
                    953:        },
                    954:        {
                    955:                .name = "subject",
                    956:                .argname = "s",
                    957:                .desc = "Subject",
                    958:                .type = OPTION_ARG,
1.33    ! tb        959:                .opt.arg = &cfg.subject,
1.19      inoguchi  960:        },
                    961:        {
                    962:                .name = "text",
                    963:                .desc = "Include or delete text MIME headers",
                    964:                .type = OPTION_VALUE_OR,
1.33    ! tb        965:                .opt.value = &cfg.flags,
1.19      inoguchi  966:                .value = CMS_TEXT,
                    967:        },
                    968:        {
                    969:                .name = "to",
                    970:                .argname = "addr",
                    971:                .desc = "To address",
                    972:                .type = OPTION_ARG,
1.33    ! tb        973:                .opt.arg = &cfg.to,
1.19      inoguchi  974:        },
                    975:        {
                    976:                .name = "uncompress",
                    977:                .desc = "Uncompress CMS CompressedData type",
                    978:                .type = OPTION_VALUE,
1.33    ! tb        979:                .opt.value = &cfg.operation,
1.19      inoguchi  980:                .value = SMIME_UNCOMPRESS,
                    981:        },
                    982:        {
                    983:                .name = "verify",
                    984:                .desc = "Verify signed message",
                    985:                .type = OPTION_VALUE,
1.33    ! tb        986:                .opt.value = &cfg.operation,
1.19      inoguchi  987:                .value = SMIME_VERIFY,
                    988:        },
                    989:        {
                    990:                .name = "verify_receipt",
                    991:                .argname = "file",
                    992:                .desc = "Verify a signed receipt in file",
                    993:                .type = OPTION_ARG_FUNC,
                    994:                .opt.argfunc = cms_opt_verify_receipt,
                    995:        },
                    996:        {
                    997:                .name = "verify_retcode",
                    998:                .desc = "Set verification error code to exit code",
                    999:                .type = OPTION_FLAG,
1.33    ! tb       1000:                .opt.flag = &cfg.verify_retcode,
1.19      inoguchi 1001:        },
                   1002:        {
                   1003:                .name = "check_ss_sig",
                   1004:                .type = OPTION_ARGV_FUNC,
                   1005:                .opt.argvfunc = cms_opt_verify_param,
                   1006:        },
                   1007:        {
                   1008:                .name = "crl_check",
                   1009:                .type = OPTION_ARGV_FUNC,
                   1010:                .opt.argvfunc = cms_opt_verify_param,
                   1011:        },
                   1012:        {
                   1013:                .name = "crl_check_all",
                   1014:                .type = OPTION_ARGV_FUNC,
                   1015:                .opt.argvfunc = cms_opt_verify_param,
                   1016:        },
                   1017:        {
                   1018:                .name = "extended_crl",
                   1019:                .type = OPTION_ARGV_FUNC,
                   1020:                .opt.argvfunc = cms_opt_verify_param,
                   1021:        },
                   1022:        {
                   1023:                .name = "ignore_critical",
                   1024:                .type = OPTION_ARGV_FUNC,
                   1025:                .opt.argvfunc = cms_opt_verify_param,
                   1026:        },
                   1027:        {
                   1028:                .name = "issuer_checks",
                   1029:                .type = OPTION_ARGV_FUNC,
                   1030:                .opt.argvfunc = cms_opt_verify_param,
                   1031:        },
                   1032:        {
                   1033:                .name = "policy",
                   1034:                .type = OPTION_ARGV_FUNC,
                   1035:                .opt.argvfunc = cms_opt_verify_param,
                   1036:        },
                   1037:        {
                   1038:                .name = "policy_check",
                   1039:                .type = OPTION_ARGV_FUNC,
                   1040:                .opt.argvfunc = cms_opt_verify_param,
                   1041:        },
                   1042:        {
                   1043:                .name = "purpose",
                   1044:                .type = OPTION_ARGV_FUNC,
                   1045:                .opt.argvfunc = cms_opt_verify_param,
                   1046:        },
                   1047:        {
                   1048:                .name = "x509_strict",
                   1049:                .type = OPTION_ARGV_FUNC,
                   1050:                .opt.argvfunc = cms_opt_verify_param,
                   1051:        },
                   1052:        {
                   1053:                .name = NULL,
                   1054:                .type = OPTION_ARGV_FUNC,
                   1055:                .opt.argvfunc = cms_opt_cipher,
                   1056:        },
                   1057:        { NULL },
                   1058: };
                   1059:
                   1060: static const struct option verify_shared_options[] = {
                   1061:        {
                   1062:                .name = "check_ss_sig",
                   1063:                .desc = "Check the root CA self-signed certificate signature",
                   1064:        },
                   1065:        {
                   1066:                .name = "crl_check",
                   1067:                .desc = "Enable CRL checking for the leaf certificate",
                   1068:        },
                   1069:        {
                   1070:                .name = "crl_check_all",
                   1071:                .desc = "Enable CRL checking for the entire certificate chain",
                   1072:        },
                   1073:        {
                   1074:                .name = "extended_crl",
                   1075:                .desc = "Enable extended CRL support",
                   1076:        },
                   1077:        {
                   1078:                .name = "ignore_critical",
                   1079:                .desc = "Disable critical extension checking",
                   1080:        },
                   1081:        {
                   1082:                .name = "issuer_checks",
                   1083:                .desc = "Enable debugging of certificate issuer checks",
                   1084:        },
                   1085:        {
                   1086:                .name = "policy",
                   1087:                .argname = "name",
                   1088:                .desc = "Add given policy to the acceptable set",
                   1089:        },
                   1090:        {
                   1091:                .name = "policy_check",
                   1092:                .desc = "Enable certificate policy checking",
                   1093:        },
                   1094:        {
                   1095:                .name = "purpose",
                   1096:                .argname = "name",
                   1097:                .desc = "Verify for the given purpose",
                   1098:        },
                   1099:        {
                   1100:                .name = "x509_strict",
                   1101:                .desc = "Use strict X.509 rules (disables workarounds)",
                   1102:        },
                   1103:        { NULL },
                   1104: };
                   1105:
                   1106: static void
                   1107: cms_usage(void)
                   1108: {
                   1109:        int i;
                   1110:
                   1111:        fprintf(stderr, "usage: cms "
                   1112:            "[-aes128 | -aes192 | -aes256 | -camellia128 |\n"
                   1113:            "    -camellia192 | -camellia256 | -des | -des3 |\n"
                   1114:            "    -rc2-40 | -rc2-64 | -rc2-128] [-CAfile file]\n"
                   1115:            "    [-CApath directory] [-binary] [-certfile file]\n"
                   1116:            "    [-certsout file] [-cmsout] [-compress] [-content file]\n"
                   1117:            "    [-crlfeol] [-data_create] [-data_out] [-debug_decrypt]\n"
                   1118:            "    [-decrypt] [-digest_create] [-digest_verify]\n"
                   1119:            "    [-econtent_type type] [-encrypt] [-EncryptedData_decrypt]\n"
                   1120:            "    [-EncryptedData_encrypt] [-from addr] [-in file]\n"
                   1121:            "    [-inform der | pem | smime] [-inkey file]\n"
                   1122:            "    [-keyform der | pem] [-keyid] [-keyopt nm:v] [-md digest]\n"
                   1123:            "    [-no_attr_verify] [-no_content_verify]\n"
                   1124:            "    [-no_signer_cert_verify] [-noattr] [-nocerts] [-nodetach]\n"
                   1125:            "    [-nointern] [-nooldmime] [-noout] [-nosigs] [-nosmimecap]\n"
                   1126:            "    [-noverify] [-out file] [-outform der | pem | smime]\n"
                   1127:            "    [-passin src] [-print] [-pwri_password arg]\n"
                   1128:            "    [-rctform der | pem | smime]\n"
                   1129:            "    [-receipt_request_all | -receipt_request_first]\n"
                   1130:            "    [-receipt_request_from addr] [-receipt_request_print]\n"
                   1131:            "    [-receipt_request_to addr] [-recip file] [-resign]\n"
                   1132:            "    [-secretkey key] [-secretkeyid id] [-sign] [-sign_receipt]\n"
                   1133:            "    [-signer file] [-stream | -indef | -noindef] [-subject s]\n"
                   1134:            "    [-text] [-to addr] [-uncompress] [-verify]\n"
                   1135:            "    [-verify_receipt file] [-verify_retcode] [cert.pem ...]\n\n");
                   1136:
                   1137:        options_usage(cms_options);
                   1138:
                   1139:        fprintf(stderr, "\nVerification options:\n\n");
                   1140:        options_usage(verify_shared_options);
                   1141:
                   1142:        fprintf(stderr, "\nValid purposes:\n\n");
                   1143:        for (i = 0; i < X509_PURPOSE_get_count(); i++) {
                   1144:                X509_PURPOSE *ptmp = X509_PURPOSE_get0(i);
                   1145:                fprintf(stderr, "  %-18s%s\n", X509_PURPOSE_get0_sname(ptmp),
                   1146:                    X509_PURPOSE_get0_name(ptmp));
                   1147:        }
                   1148: }
                   1149:
1.1       jsing    1150: int
                   1151: cms_main(int argc, char **argv)
                   1152: {
                   1153:        int ret = 0;
                   1154:        char **args;
1.19      inoguchi 1155:        int argsused = 0;
1.1       jsing    1156:        const char *inmode = "r", *outmode = "w";
                   1157:        CMS_ContentInfo *cms = NULL, *rcms = NULL;
                   1158:        X509_STORE *store = NULL;
1.19      inoguchi 1159:        X509 *recip = NULL, *signer = NULL;
1.1       jsing    1160:        EVP_PKEY *key = NULL;
1.19      inoguchi 1161:        STACK_OF(X509) *other = NULL;
1.1       jsing    1162:        BIO *in = NULL, *out = NULL, *indata = NULL, *rctin = NULL;
                   1163:        int badarg = 0;
                   1164:        CMS_ReceiptRequest *rr = NULL;
1.19      inoguchi 1165:        char *passin = NULL;
                   1166:        unsigned char *pwri_tmp = NULL;
1.4       doug     1167:
1.31      joshua   1168:        if (pledge("stdio rpath wpath cpath tty", NULL) == -1) {
                   1169:                perror("pledge");
                   1170:                exit(1);
1.4       doug     1171:        }
1.1       jsing    1172:
1.33    ! tb       1173:        memset(&cfg, 0, sizeof(cfg));
        !          1174:        cfg.flags = CMS_DETACHED;
        !          1175:        cfg.rr_allorfirst = -1;
        !          1176:        cfg.informat = FORMAT_SMIME;
        !          1177:        cfg.outformat = FORMAT_SMIME;
        !          1178:        cfg.rctformat = FORMAT_SMIME;
        !          1179:        cfg.keyform = FORMAT_PEM;
1.19      inoguchi 1180:        if (options_parse(argc, argv, cms_options, NULL, &argsused) != 0) {
                   1181:                goto argerr;
                   1182:        }
                   1183:        args = argv + argsused;
1.1       jsing    1184:        ret = 1;
                   1185:
1.33    ! tb       1186:        if (((cfg.rr_allorfirst != -1) || cfg.rr_from != NULL) &&
        !          1187:            cfg.rr_to == NULL) {
1.1       jsing    1188:                BIO_puts(bio_err, "No Signed Receipts Recipients\n");
                   1189:                goto argerr;
                   1190:        }
1.33    ! tb       1191:        if (!(cfg.operation & SMIME_SIGNERS) &&
        !          1192:            (cfg.rr_to != NULL || cfg.rr_from != NULL)) {
1.1       jsing    1193:                BIO_puts(bio_err, "Signed receipts only allowed with -sign\n");
                   1194:                goto argerr;
                   1195:        }
1.33    ! tb       1196:        if (!(cfg.operation & SMIME_SIGNERS) &&
        !          1197:            (cfg.skkeys != NULL || cfg.sksigners != NULL)) {
1.1       jsing    1198:                BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
                   1199:                goto argerr;
                   1200:        }
1.33    ! tb       1201:        if (cfg.operation & SMIME_SIGNERS) {
        !          1202:                if (cfg.keyfile != NULL &&
        !          1203:                    cfg.signerfile == NULL) {
1.1       jsing    1204:                        BIO_puts(bio_err, "Illegal -inkey without -signer\n");
                   1205:                        goto argerr;
                   1206:                }
                   1207:                /* Check to see if any final signer needs to be appended */
1.33    ! tb       1208:                if (cfg.signerfile != NULL) {
        !          1209:                        if (cfg.sksigners == NULL &&
        !          1210:                            (cfg.sksigners =
1.24      inoguchi 1211:                            sk_OPENSSL_STRING_new_null()) == NULL)
1.16      inoguchi 1212:                                goto end;
1.33    ! tb       1213:                        if (!sk_OPENSSL_STRING_push(cfg.sksigners,
        !          1214:                            cfg.signerfile))
1.15      inoguchi 1215:                                goto end;
1.33    ! tb       1216:                        if (cfg.skkeys == NULL &&
        !          1217:                            (cfg.skkeys =
1.24      inoguchi 1218:                            sk_OPENSSL_STRING_new_null()) == NULL)
1.16      inoguchi 1219:                                goto end;
1.33    ! tb       1220:                        if (cfg.keyfile == NULL)
        !          1221:                                cfg.keyfile = cfg.signerfile;
        !          1222:                        if (!sk_OPENSSL_STRING_push(cfg.skkeys,
        !          1223:                            cfg.keyfile))
1.15      inoguchi 1224:                                goto end;
1.1       jsing    1225:                }
1.33    ! tb       1226:                if (cfg.sksigners == NULL) {
1.1       jsing    1227:                        BIO_printf(bio_err,
                   1228:                            "No signer certificate specified\n");
                   1229:                        badarg = 1;
                   1230:                }
1.33    ! tb       1231:                cfg.signerfile = NULL;
        !          1232:                cfg.keyfile = NULL;
        !          1233:        } else if (cfg.operation == SMIME_DECRYPT) {
        !          1234:                if (cfg.recipfile == NULL &&
        !          1235:                    cfg.keyfile == NULL &&
        !          1236:                    cfg.secret_key == NULL &&
        !          1237:                    cfg.pwri_pass == NULL) {
1.1       jsing    1238:                        BIO_printf(bio_err,
                   1239:                            "No recipient certificate or key specified\n");
                   1240:                        badarg = 1;
                   1241:                }
1.33    ! tb       1242:        } else if (cfg.operation == SMIME_ENCRYPT) {
        !          1243:                if (*args == NULL && cfg.secret_key == NULL &&
        !          1244:                    cfg.pwri_pass == NULL &&
        !          1245:                    cfg.encerts == NULL) {
1.1       jsing    1246:                        BIO_printf(bio_err,
                   1247:                            "No recipient(s) certificate(s) specified\n");
                   1248:                        badarg = 1;
                   1249:                }
1.33    ! tb       1250:        } else if (!cfg.operation) {
1.1       jsing    1251:                badarg = 1;
1.24      inoguchi 1252:        }
1.1       jsing    1253:
                   1254:        if (badarg) {
1.13      jsing    1255:  argerr:
1.19      inoguchi 1256:                cms_usage();
1.1       jsing    1257:                goto end;
                   1258:        }
                   1259:
1.33    ! tb       1260:        if (!app_passwd(bio_err, cfg.passargin, NULL, &passin, NULL)) {
1.1       jsing    1261:                BIO_printf(bio_err, "Error getting password\n");
                   1262:                goto end;
                   1263:        }
                   1264:        ret = 2;
                   1265:
1.33    ! tb       1266:        if (!(cfg.operation & SMIME_SIGNERS))
        !          1267:                cfg.flags &= ~CMS_DETACHED;
1.1       jsing    1268:
1.33    ! tb       1269:        if (cfg.operation & SMIME_OP) {
        !          1270:                if (cfg.outformat == FORMAT_ASN1)
1.1       jsing    1271:                        outmode = "wb";
                   1272:        } else {
1.33    ! tb       1273:                if (cfg.flags & CMS_BINARY)
1.1       jsing    1274:                        outmode = "wb";
                   1275:        }
                   1276:
1.33    ! tb       1277:        if (cfg.operation & SMIME_IP) {
        !          1278:                if (cfg.informat == FORMAT_ASN1)
1.1       jsing    1279:                        inmode = "rb";
                   1280:        } else {
1.33    ! tb       1281:                if (cfg.flags & CMS_BINARY)
1.1       jsing    1282:                        inmode = "rb";
                   1283:        }
                   1284:
1.33    ! tb       1285:        if (cfg.operation == SMIME_ENCRYPT) {
        !          1286:                if (cfg.cipher == NULL) {
1.1       jsing    1287: #ifndef OPENSSL_NO_DES
1.33    ! tb       1288:                        cfg.cipher = EVP_des_ede3_cbc();
1.1       jsing    1289: #else
                   1290:                        BIO_printf(bio_err, "No cipher selected\n");
                   1291:                        goto end;
                   1292: #endif
                   1293:                }
1.33    ! tb       1294:                if (cfg.secret_key != NULL &&
        !          1295:                    cfg.secret_keyid == NULL) {
1.1       jsing    1296:                        BIO_printf(bio_err, "No secret key id\n");
                   1297:                        goto end;
                   1298:                }
1.33    ! tb       1299:                if (*args != NULL && cfg.encerts == NULL)
        !          1300:                        if ((cfg.encerts = sk_X509_new_null()) == NULL)
1.16      inoguchi 1301:                                goto end;
1.1       jsing    1302:                while (*args) {
1.33    ! tb       1303:                        if ((cfg.cert = load_cert(bio_err, *args,
1.24      inoguchi 1304:                            FORMAT_PEM, NULL,
                   1305:                            "recipient certificate file")) == NULL)
1.1       jsing    1306:                                goto end;
1.33    ! tb       1307:                        if (!sk_X509_push(cfg.encerts, cfg.cert))
1.15      inoguchi 1308:                                goto end;
1.33    ! tb       1309:                        cfg.cert = NULL;
1.1       jsing    1310:                        args++;
                   1311:                }
                   1312:        }
1.33    ! tb       1313:        if (cfg.certfile != NULL) {
        !          1314:                if ((other = load_certs(bio_err, cfg.certfile,
1.24      inoguchi 1315:                    FORMAT_PEM, NULL, "certificate file")) == NULL) {
1.1       jsing    1316:                        ERR_print_errors(bio_err);
                   1317:                        goto end;
                   1318:                }
                   1319:        }
1.33    ! tb       1320:        if (cfg.recipfile != NULL &&
        !          1321:            (cfg.operation == SMIME_DECRYPT)) {
        !          1322:                if ((recip = load_cert(bio_err, cfg.recipfile,
1.24      inoguchi 1323:                    FORMAT_PEM, NULL, "recipient certificate file")) == NULL) {
1.1       jsing    1324:                        ERR_print_errors(bio_err);
                   1325:                        goto end;
                   1326:                }
                   1327:        }
1.33    ! tb       1328:        if (cfg.operation == SMIME_SIGN_RECEIPT) {
        !          1329:                if ((signer = load_cert(bio_err, cfg.signerfile,
1.24      inoguchi 1330:                    FORMAT_PEM, NULL,
1.22      inoguchi 1331:                    "receipt signer certificate file")) == NULL) {
1.1       jsing    1332:                        ERR_print_errors(bio_err);
                   1333:                        goto end;
                   1334:                }
                   1335:        }
1.33    ! tb       1336:        if (cfg.operation == SMIME_DECRYPT) {
        !          1337:                if (cfg.keyfile == NULL)
        !          1338:                        cfg.keyfile = cfg.recipfile;
        !          1339:        } else if ((cfg.operation == SMIME_SIGN) ||
        !          1340:            (cfg.operation == SMIME_SIGN_RECEIPT)) {
        !          1341:                if (cfg.keyfile == NULL)
        !          1342:                        cfg.keyfile = cfg.signerfile;
1.24      inoguchi 1343:        } else {
1.33    ! tb       1344:                cfg.keyfile = NULL;
1.24      inoguchi 1345:        }
1.1       jsing    1346:
1.33    ! tb       1347:        if (cfg.keyfile != NULL) {
        !          1348:                key = load_key(bio_err, cfg.keyfile, cfg.keyform,
1.24      inoguchi 1349:                    0, passin, "signing key file");
1.22      inoguchi 1350:                if (key == NULL)
1.1       jsing    1351:                        goto end;
                   1352:        }
1.33    ! tb       1353:        if (cfg.infile != NULL) {
        !          1354:                if ((in = BIO_new_file(cfg.infile, inmode)) == NULL) {
1.1       jsing    1355:                        BIO_printf(bio_err,
1.33    ! tb       1356:                            "Can't open input file %s\n", cfg.infile);
1.1       jsing    1357:                        goto end;
                   1358:                }
1.24      inoguchi 1359:        } else {
1.23      inoguchi 1360:                if ((in = BIO_new_fp(stdin, BIO_NOCLOSE)) == NULL)
                   1361:                        goto end;
1.24      inoguchi 1362:        }
1.1       jsing    1363:
1.33    ! tb       1364:        if (cfg.operation & SMIME_IP) {
        !          1365:                if (cfg.informat == FORMAT_SMIME)
1.1       jsing    1366:                        cms = SMIME_read_CMS(in, &indata);
1.33    ! tb       1367:                else if (cfg.informat == FORMAT_PEM)
1.1       jsing    1368:                        cms = PEM_read_bio_CMS(in, NULL, NULL, NULL);
1.33    ! tb       1369:                else if (cfg.informat == FORMAT_ASN1)
1.1       jsing    1370:                        cms = d2i_CMS_bio(in, NULL);
                   1371:                else {
                   1372:                        BIO_printf(bio_err, "Bad input format for CMS file\n");
                   1373:                        goto end;
                   1374:                }
                   1375:
1.22      inoguchi 1376:                if (cms == NULL) {
1.1       jsing    1377:                        BIO_printf(bio_err, "Error reading S/MIME message\n");
                   1378:                        goto end;
                   1379:                }
1.33    ! tb       1380:                if (cfg.contfile != NULL) {
1.1       jsing    1381:                        BIO_free(indata);
1.33    ! tb       1382:                        if ((indata = BIO_new_file(cfg.contfile,
1.24      inoguchi 1383:                            "rb")) == NULL) {
1.1       jsing    1384:                                BIO_printf(bio_err,
1.24      inoguchi 1385:                                    "Can't read content file %s\n",
1.33    ! tb       1386:                                    cfg.contfile);
1.1       jsing    1387:                                goto end;
                   1388:                        }
                   1389:                }
1.33    ! tb       1390:                if (cfg.certsoutfile != NULL) {
1.12      jsing    1391:                        STACK_OF(X509) *allcerts;
1.17      inoguchi 1392:                        if ((allcerts = CMS_get1_certs(cms)) == NULL)
                   1393:                                goto end;
1.33    ! tb       1394:                        if (!save_certs(cfg.certsoutfile, allcerts)) {
1.1       jsing    1395:                                BIO_printf(bio_err,
                   1396:                                    "Error writing certs to %s\n",
1.33    ! tb       1397:                                    cfg.certsoutfile);
1.29      inoguchi 1398:                                sk_X509_pop_free(allcerts, X509_free);
1.1       jsing    1399:                                ret = 5;
                   1400:                                goto end;
                   1401:                        }
                   1402:                        sk_X509_pop_free(allcerts, X509_free);
                   1403:                }
                   1404:        }
1.33    ! tb       1405:        if (cfg.rctfile != NULL) {
        !          1406:                char *rctmode = (cfg.rctformat == FORMAT_ASN1) ?
1.24      inoguchi 1407:                    "rb" : "r";
1.33    ! tb       1408:                if ((rctin = BIO_new_file(cfg.rctfile, rctmode)) == NULL) {
1.1       jsing    1409:                        BIO_printf(bio_err,
1.33    ! tb       1410:                            "Can't open receipt file %s\n", cfg.rctfile);
1.1       jsing    1411:                        goto end;
                   1412:                }
1.33    ! tb       1413:                if (cfg.rctformat == FORMAT_SMIME)
1.1       jsing    1414:                        rcms = SMIME_read_CMS(rctin, NULL);
1.33    ! tb       1415:                else if (cfg.rctformat == FORMAT_PEM)
1.1       jsing    1416:                        rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL);
1.33    ! tb       1417:                else if (cfg.rctformat == FORMAT_ASN1)
1.1       jsing    1418:                        rcms = d2i_CMS_bio(rctin, NULL);
                   1419:                else {
                   1420:                        BIO_printf(bio_err, "Bad input format for receipt\n");
                   1421:                        goto end;
                   1422:                }
                   1423:
1.22      inoguchi 1424:                if (rcms == NULL) {
1.1       jsing    1425:                        BIO_printf(bio_err, "Error reading receipt\n");
                   1426:                        goto end;
                   1427:                }
                   1428:        }
1.33    ! tb       1429:        if (cfg.outfile != NULL) {
        !          1430:                if ((out = BIO_new_file(cfg.outfile, outmode)) == NULL) {
1.1       jsing    1431:                        BIO_printf(bio_err,
1.33    ! tb       1432:                            "Can't open output file %s\n", cfg.outfile);
1.1       jsing    1433:                        goto end;
                   1434:                }
                   1435:        } else {
1.23      inoguchi 1436:                if ((out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL)
                   1437:                        goto end;
1.1       jsing    1438:        }
                   1439:
1.33    ! tb       1440:        if ((cfg.operation == SMIME_VERIFY) ||
        !          1441:            (cfg.operation == SMIME_VERIFY_RECEIPT)) {
        !          1442:                if ((store = setup_verify(bio_err, cfg.CAfile,
        !          1443:                    cfg.CApath)) == NULL)
1.1       jsing    1444:                        goto end;
                   1445:                X509_STORE_set_verify_cb(store, cms_cb);
1.33    ! tb       1446:                if (cfg.vpm != NULL) {
        !          1447:                        if (!X509_STORE_set1_param(store, cfg.vpm))
1.23      inoguchi 1448:                                goto end;
                   1449:                }
1.1       jsing    1450:        }
                   1451:        ret = 3;
                   1452:
1.33    ! tb       1453:        if (cfg.operation == SMIME_DATA_CREATE) {
        !          1454:                cms = CMS_data_create(in, cfg.flags);
        !          1455:        } else if (cfg.operation == SMIME_DIGEST_CREATE) {
        !          1456:                cms = CMS_digest_create(in, cfg.sign_md,
        !          1457:                    cfg.flags);
        !          1458:        } else if (cfg.operation == SMIME_COMPRESS) {
        !          1459:                cms = CMS_compress(in, -1, cfg.flags);
        !          1460:        } else if (cfg.operation == SMIME_ENCRYPT) {
1.14      inoguchi 1461:                int i;
1.33    ! tb       1462:                cfg.flags |= CMS_PARTIAL;
        !          1463:                cms = CMS_encrypt(NULL, in, cfg.cipher,
        !          1464:                    cfg.flags);
1.14      inoguchi 1465:                if (cms == NULL)
1.1       jsing    1466:                        goto end;
1.33    ! tb       1467:                for (i = 0; i < sk_X509_num(cfg.encerts); i++) {
1.14      inoguchi 1468:                        CMS_RecipientInfo *ri;
1.15      inoguchi 1469:                        struct cms_key_param *kparam;
1.33    ! tb       1470:                        int tflags = cfg.flags;
1.23      inoguchi 1471:                        X509 *x;
1.32      tb       1472:
1.33    ! tb       1473:                        if ((x = sk_X509_value(cfg.encerts, i)) == NULL)
1.23      inoguchi 1474:                                goto end;
1.33    ! tb       1475:                        for (kparam = cfg.key_first; kparam != NULL;
1.24      inoguchi 1476:                            kparam = kparam->next) {
1.14      inoguchi 1477:                                if (kparam->idx == i) {
                   1478:                                        tflags |= CMS_KEY_PARAM;
                   1479:                                        break;
                   1480:                                }
                   1481:                        }
                   1482:                        ri = CMS_add1_recipient_cert(cms, x, tflags);
                   1483:                        if (ri == NULL)
                   1484:                                goto end;
                   1485:                        if (kparam != NULL) {
                   1486:                                EVP_PKEY_CTX *pctx;
1.24      inoguchi 1487:                                if ((pctx = CMS_RecipientInfo_get0_pkey_ctx(
                   1488:                                    ri)) == NULL)
1.17      inoguchi 1489:                                        goto end;
1.14      inoguchi 1490:                                if (!cms_set_pkey_param(pctx, kparam->param))
                   1491:                                        goto end;
                   1492:                        }
                   1493:                }
                   1494:
1.33    ! tb       1495:                if (cfg.secret_key != NULL) {
1.24      inoguchi 1496:                        if (CMS_add0_recipient_key(cms, NID_undef,
1.33    ! tb       1497:                            cfg.secret_key, cfg.secret_keylen,
        !          1498:                            cfg.secret_keyid, cfg.secret_keyidlen,
1.22      inoguchi 1499:                            NULL, NULL, NULL) == NULL)
1.1       jsing    1500:                                goto end;
                   1501:                        /* NULL these because call absorbs them */
1.33    ! tb       1502:                        cfg.secret_key = NULL;
        !          1503:                        cfg.secret_keyid = NULL;
1.1       jsing    1504:                }
1.33    ! tb       1505:                if (cfg.pwri_pass != NULL) {
        !          1506:                        pwri_tmp = strdup(cfg.pwri_pass);
1.22      inoguchi 1507:                        if (pwri_tmp == NULL)
1.1       jsing    1508:                                goto end;
1.22      inoguchi 1509:                        if (CMS_add0_recipient_password(cms, -1, NID_undef,
                   1510:                            NID_undef, pwri_tmp, -1, NULL) == NULL)
1.1       jsing    1511:                                goto end;
                   1512:                        pwri_tmp = NULL;
                   1513:                }
1.33    ! tb       1514:                if (!(cfg.flags & CMS_STREAM)) {
        !          1515:                        if (!CMS_final(cms, in, NULL, cfg.flags))
1.1       jsing    1516:                                goto end;
                   1517:                }
1.33    ! tb       1518:        } else if (cfg.operation == SMIME_ENCRYPTED_ENCRYPT) {
        !          1519:                cms = CMS_EncryptedData_encrypt(in, cfg.cipher,
        !          1520:                    cfg.secret_key, cfg.secret_keylen,
        !          1521:                    cfg.flags);
1.1       jsing    1522:
1.33    ! tb       1523:        } else if (cfg.operation == SMIME_SIGN_RECEIPT) {
1.1       jsing    1524:                CMS_ContentInfo *srcms = NULL;
1.12      jsing    1525:                STACK_OF(CMS_SignerInfo) *sis;
1.1       jsing    1526:                CMS_SignerInfo *si;
                   1527:                sis = CMS_get0_SignerInfos(cms);
1.22      inoguchi 1528:                if (sis == NULL)
1.1       jsing    1529:                        goto end;
                   1530:                si = sk_CMS_SignerInfo_value(sis, 0);
1.23      inoguchi 1531:                if (si == NULL)
                   1532:                        goto end;
1.24      inoguchi 1533:                srcms = CMS_sign_receipt(si, signer, key, other,
1.33    ! tb       1534:                    cfg.flags);
1.22      inoguchi 1535:                if (srcms == NULL)
1.1       jsing    1536:                        goto end;
                   1537:                CMS_ContentInfo_free(cms);
                   1538:                cms = srcms;
1.33    ! tb       1539:        } else if (cfg.operation & SMIME_SIGNERS) {
1.1       jsing    1540:                int i;
                   1541:                /*
                   1542:                 * If detached data content we enable streaming if S/MIME
                   1543:                 * output format.
                   1544:                 */
1.33    ! tb       1545:                if (cfg.operation == SMIME_SIGN) {
1.1       jsing    1546:
1.33    ! tb       1547:                        if (cfg.flags & CMS_DETACHED) {
        !          1548:                                if (cfg.outformat == FORMAT_SMIME)
        !          1549:                                        cfg.flags |= CMS_STREAM;
1.1       jsing    1550:                        }
1.33    ! tb       1551:                        cfg.flags |= CMS_PARTIAL;
        !          1552:                        cms = CMS_sign(NULL, NULL, other, in, cfg.flags);
1.22      inoguchi 1553:                        if (cms == NULL)
1.1       jsing    1554:                                goto end;
1.33    ! tb       1555:                        if (cfg.econtent_type != NULL)
1.24      inoguchi 1556:                                if (!CMS_set1_eContentType(cms,
1.33    ! tb       1557:                                    cfg.econtent_type))
1.17      inoguchi 1558:                                        goto end;
1.1       jsing    1559:
1.33    ! tb       1560:                        if (cfg.rr_to != NULL) {
        !          1561:                                rr = make_receipt_request(cfg.rr_to,
        !          1562:                                    cfg.rr_allorfirst,
        !          1563:                                    cfg.rr_from);
1.22      inoguchi 1564:                                if (rr == NULL) {
1.1       jsing    1565:                                        BIO_puts(bio_err,
                   1566:                                            "Signed Receipt Request Creation Error\n");
                   1567:                                        goto end;
                   1568:                                }
                   1569:                        }
1.24      inoguchi 1570:                } else {
1.33    ! tb       1571:                        cfg.flags |= CMS_REUSE_DIGEST;
1.24      inoguchi 1572:                }
                   1573:
1.33    ! tb       1574:                for (i = 0; i < sk_OPENSSL_STRING_num(cfg.sksigners); i++) {
1.1       jsing    1575:                        CMS_SignerInfo *si;
1.15      inoguchi 1576:                        struct cms_key_param *kparam;
1.33    ! tb       1577:                        int tflags = cfg.flags;
1.14      inoguchi 1578:
1.33    ! tb       1579:                        cfg.signerfile = sk_OPENSSL_STRING_value(
        !          1580:                            cfg.sksigners, i);
        !          1581:                        cfg.keyfile = sk_OPENSSL_STRING_value(
        !          1582:                            cfg.skkeys, i);
1.24      inoguchi 1583:
1.33    ! tb       1584:                        signer = load_cert(bio_err, cfg.signerfile,
1.24      inoguchi 1585:                            FORMAT_PEM, NULL, "signer certificate");
1.22      inoguchi 1586:                        if (signer == NULL)
1.1       jsing    1587:                                goto end;
1.33    ! tb       1588:                        key = load_key(bio_err, cfg.keyfile,
        !          1589:                            cfg.keyform, 0, passin, "signing key file");
1.22      inoguchi 1590:                        if (key == NULL)
1.1       jsing    1591:                                goto end;
1.33    ! tb       1592:                        for (kparam = cfg.key_first; kparam != NULL;
1.24      inoguchi 1593:                            kparam = kparam->next) {
1.14      inoguchi 1594:                                if (kparam->idx == i) {
                   1595:                                        tflags |= CMS_KEY_PARAM;
                   1596:                                        break;
                   1597:                                }
                   1598:                        }
1.24      inoguchi 1599:                        si = CMS_add1_signer(cms, signer, key,
1.33    ! tb       1600:                            cfg.sign_md, tflags);
1.14      inoguchi 1601:                        if (si == NULL)
1.1       jsing    1602:                                goto end;
1.14      inoguchi 1603:                        if (kparam != NULL) {
                   1604:                                EVP_PKEY_CTX *pctx;
1.24      inoguchi 1605:                                if ((pctx = CMS_SignerInfo_get0_pkey_ctx(
                   1606:                                    si)) == NULL)
1.17      inoguchi 1607:                                        goto end;
1.14      inoguchi 1608:                                if (!cms_set_pkey_param(pctx, kparam->param))
                   1609:                                        goto end;
                   1610:                        }
1.22      inoguchi 1611:                        if (rr != NULL && !CMS_add1_ReceiptRequest(si, rr))
1.1       jsing    1612:                                goto end;
                   1613:                        X509_free(signer);
                   1614:                        signer = NULL;
                   1615:                        EVP_PKEY_free(key);
                   1616:                        key = NULL;
                   1617:                }
                   1618:                /* If not streaming or resigning finalize structure */
1.33    ! tb       1619:                if ((cfg.operation == SMIME_SIGN) &&
        !          1620:                    !(cfg.flags & CMS_STREAM)) {
        !          1621:                        if (!CMS_final(cms, in, NULL, cfg.flags))
1.1       jsing    1622:                                goto end;
                   1623:                }
                   1624:        }
1.22      inoguchi 1625:        if (cms == NULL) {
1.1       jsing    1626:                BIO_printf(bio_err, "Error creating CMS structure\n");
                   1627:                goto end;
                   1628:        }
                   1629:        ret = 4;
1.33    ! tb       1630:        if (cfg.operation == SMIME_DECRYPT) {
        !          1631:                if (cfg.flags & CMS_DEBUG_DECRYPT)
1.24      inoguchi 1632:                        CMS_decrypt(cms, NULL, NULL, NULL, NULL,
1.33    ! tb       1633:                            cfg.flags);
1.19      inoguchi 1634:
1.33    ! tb       1635:                if (cfg.secret_key != NULL) {
        !          1636:                        if (!CMS_decrypt_set1_key(cms, cfg.secret_key,
        !          1637:                            cfg.secret_keylen, cfg.secret_keyid,
        !          1638:                            cfg.secret_keyidlen)) {
1.1       jsing    1639:                                BIO_puts(bio_err,
                   1640:                                    "Error decrypting CMS using secret key\n");
                   1641:                                goto end;
                   1642:                        }
                   1643:                }
1.22      inoguchi 1644:                if (key != NULL) {
1.1       jsing    1645:                        if (!CMS_decrypt_set1_pkey(cms, key, recip)) {
                   1646:                                BIO_puts(bio_err,
                   1647:                                    "Error decrypting CMS using private key\n");
                   1648:                                goto end;
                   1649:                        }
                   1650:                }
1.33    ! tb       1651:                if (cfg.pwri_pass != NULL) {
1.24      inoguchi 1652:                        if (!CMS_decrypt_set1_password(cms,
1.33    ! tb       1653:                            cfg.pwri_pass, -1)) {
1.1       jsing    1654:                                BIO_puts(bio_err,
                   1655:                                    "Error decrypting CMS using password\n");
                   1656:                                goto end;
                   1657:                        }
                   1658:                }
1.24      inoguchi 1659:                if (!CMS_decrypt(cms, NULL, NULL, indata, out,
1.33    ! tb       1660:                    cfg.flags)) {
1.1       jsing    1661:                        BIO_printf(bio_err, "Error decrypting CMS structure\n");
                   1662:                        goto end;
                   1663:                }
1.33    ! tb       1664:        } else if (cfg.operation == SMIME_DATAOUT) {
        !          1665:                if (!CMS_data(cms, out, cfg.flags))
1.1       jsing    1666:                        goto end;
1.33    ! tb       1667:        } else if (cfg.operation == SMIME_UNCOMPRESS) {
        !          1668:                if (!CMS_uncompress(cms, indata, out, cfg.flags))
1.1       jsing    1669:                        goto end;
1.33    ! tb       1670:        } else if (cfg.operation == SMIME_DIGEST_VERIFY) {
        !          1671:                if (CMS_digest_verify(cms, indata, out, cfg.flags) > 0)
1.1       jsing    1672:                        BIO_printf(bio_err, "Verification successful\n");
                   1673:                else {
                   1674:                        BIO_printf(bio_err, "Verification failure\n");
                   1675:                        goto end;
                   1676:                }
1.33    ! tb       1677:        } else if (cfg.operation == SMIME_ENCRYPTED_DECRYPT) {
        !          1678:                if (!CMS_EncryptedData_decrypt(cms, cfg.secret_key,
        !          1679:                    cfg.secret_keylen, indata, out, cfg.flags))
1.1       jsing    1680:                        goto end;
1.33    ! tb       1681:        } else if (cfg.operation == SMIME_VERIFY) {
1.24      inoguchi 1682:                if (CMS_verify(cms, other, store, indata, out,
1.33    ! tb       1683:                    cfg.flags) > 0) {
1.1       jsing    1684:                        BIO_printf(bio_err, "Verification successful\n");
1.24      inoguchi 1685:                } else {
1.1       jsing    1686:                        BIO_printf(bio_err, "Verification failure\n");
1.33    ! tb       1687:                        if (cfg.verify_retcode)
1.1       jsing    1688:                                ret = verify_err + 32;
                   1689:                        goto end;
                   1690:                }
1.33    ! tb       1691:                if (cfg.signerfile != NULL) {
1.12      jsing    1692:                        STACK_OF(X509) *signers;
1.17      inoguchi 1693:                        if ((signers = CMS_get0_signers(cms)) == NULL)
                   1694:                                goto end;
1.33    ! tb       1695:                        if (!save_certs(cfg.signerfile, signers)) {
1.1       jsing    1696:                                BIO_printf(bio_err,
                   1697:                                    "Error writing signers to %s\n",
1.33    ! tb       1698:                                    cfg.signerfile);
1.29      inoguchi 1699:                                sk_X509_free(signers);
1.1       jsing    1700:                                ret = 5;
                   1701:                                goto end;
                   1702:                        }
                   1703:                        sk_X509_free(signers);
                   1704:                }
1.33    ! tb       1705:                if (cfg.rr_print)
1.1       jsing    1706:                        receipt_request_print(bio_err, cms);
                   1707:
1.33    ! tb       1708:        } else if (cfg.operation == SMIME_VERIFY_RECEIPT) {
1.24      inoguchi 1709:                if (CMS_verify_receipt(rcms, cms, other, store,
1.33    ! tb       1710:                    cfg.flags) > 0) {
1.1       jsing    1711:                        BIO_printf(bio_err, "Verification successful\n");
1.24      inoguchi 1712:                } else {
1.1       jsing    1713:                        BIO_printf(bio_err, "Verification failure\n");
                   1714:                        goto end;
                   1715:                }
                   1716:        } else {
1.33    ! tb       1717:                if (cfg.noout) {
        !          1718:                        if (cfg.print &&
1.17      inoguchi 1719:                            !CMS_ContentInfo_print_ctx(out, cms, 0, NULL))
                   1720:                                goto end;
1.33    ! tb       1721:                } else if (cfg.outformat == FORMAT_SMIME) {
        !          1722:                        if (cfg.to != NULL)
        !          1723:                                BIO_printf(out, "To: %s\n", cfg.to);
        !          1724:                        if (cfg.from != NULL)
        !          1725:                                BIO_printf(out, "From: %s\n", cfg.from);
        !          1726:                        if (cfg.subject != NULL)
1.24      inoguchi 1727:                                BIO_printf(out, "Subject: %s\n",
1.33    ! tb       1728:                                    cfg.subject);
        !          1729:                        if (cfg.operation == SMIME_RESIGN)
1.24      inoguchi 1730:                                ret = SMIME_write_CMS(out, cms, indata,
1.33    ! tb       1731:                                    cfg.flags);
1.1       jsing    1732:                        else
1.24      inoguchi 1733:                                ret = SMIME_write_CMS(out, cms, in,
1.33    ! tb       1734:                                    cfg.flags);
        !          1735:                } else if (cfg.outformat == FORMAT_PEM) {
1.24      inoguchi 1736:                        ret = PEM_write_bio_CMS_stream(out, cms, in,
1.33    ! tb       1737:                            cfg.flags);
        !          1738:                } else if (cfg.outformat == FORMAT_ASN1) {
        !          1739:                        ret = i2d_CMS_bio_stream(out, cms, in, cfg.flags);
1.24      inoguchi 1740:                } else {
1.1       jsing    1741:                        BIO_printf(bio_err, "Bad output format for CMS file\n");
                   1742:                        goto end;
                   1743:                }
                   1744:                if (ret <= 0) {
                   1745:                        ret = 6;
                   1746:                        goto end;
                   1747:                }
                   1748:        }
                   1749:        ret = 0;
                   1750:
1.13      jsing    1751:  end:
1.1       jsing    1752:        if (ret)
                   1753:                ERR_print_errors(bio_err);
1.11      jsing    1754:
1.33    ! tb       1755:        sk_X509_pop_free(cfg.encerts, X509_free);
1.1       jsing    1756:        sk_X509_pop_free(other, X509_free);
1.33    ! tb       1757:        X509_VERIFY_PARAM_free(cfg.vpm);
        !          1758:        sk_OPENSSL_STRING_free(cfg.sksigners);
        !          1759:        sk_OPENSSL_STRING_free(cfg.skkeys);
        !          1760:        free(cfg.secret_key);
        !          1761:        free(cfg.secret_keyid);
1.1       jsing    1762:        free(pwri_tmp);
1.33    ! tb       1763:        ASN1_OBJECT_free(cfg.econtent_type);
1.11      jsing    1764:        CMS_ReceiptRequest_free(rr);
1.33    ! tb       1765:        sk_OPENSSL_STRING_free(cfg.rr_to);
        !          1766:        sk_OPENSSL_STRING_free(cfg.rr_from);
        !          1767:        for (cfg.key_param = cfg.key_first; cfg.key_param;) {
1.15      inoguchi 1768:                struct cms_key_param *tparam;
1.33    ! tb       1769:                sk_OPENSSL_STRING_free(cfg.key_param->param);
        !          1770:                tparam = cfg.key_param->next;
        !          1771:                free(cfg.key_param);
        !          1772:                cfg.key_param = tparam;
1.14      inoguchi 1773:        }
1.1       jsing    1774:        X509_STORE_free(store);
1.33    ! tb       1775:        X509_free(cfg.cert);
1.1       jsing    1776:        X509_free(recip);
                   1777:        X509_free(signer);
                   1778:        EVP_PKEY_free(key);
                   1779:        CMS_ContentInfo_free(cms);
                   1780:        CMS_ContentInfo_free(rcms);
                   1781:        BIO_free(rctin);
                   1782:        BIO_free(in);
                   1783:        BIO_free(indata);
                   1784:        BIO_free_all(out);
                   1785:        free(passin);
1.11      jsing    1786:
1.1       jsing    1787:        return (ret);
                   1788: }
                   1789:
                   1790: static int
1.12      jsing    1791: save_certs(char *signerfile, STACK_OF(X509) *signers)
1.1       jsing    1792: {
                   1793:        int i;
                   1794:        BIO *tmp;
                   1795:
1.22      inoguchi 1796:        if (signerfile == NULL)
1.1       jsing    1797:                return 1;
                   1798:        tmp = BIO_new_file(signerfile, "w");
1.22      inoguchi 1799:        if (tmp == NULL)
1.1       jsing    1800:                return 0;
                   1801:        for (i = 0; i < sk_X509_num(signers); i++)
                   1802:                PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
                   1803:        BIO_free(tmp);
                   1804:        return 1;
                   1805: }
                   1806:
                   1807: /* Minimal callback just to output policy info (if any) */
                   1808:
                   1809: static int
1.12      jsing    1810: cms_cb(int ok, X509_STORE_CTX *ctx)
1.1       jsing    1811: {
                   1812:        int error;
                   1813:
                   1814:        error = X509_STORE_CTX_get_error(ctx);
                   1815:
                   1816:        verify_err = error;
                   1817:
                   1818:        if ((error != X509_V_ERR_NO_EXPLICIT_POLICY) &&
                   1819:            ((error != X509_V_OK) || (ok != 2)))
                   1820:                return ok;
                   1821:
                   1822:        policies_print(NULL, ctx);
                   1823:
                   1824:        return ok;
                   1825: }
                   1826:
                   1827: static void
1.12      jsing    1828: gnames_stack_print(BIO *out, STACK_OF(GENERAL_NAMES) *gns)
1.1       jsing    1829: {
1.12      jsing    1830:        STACK_OF(GENERAL_NAME) *gens;
1.1       jsing    1831:        GENERAL_NAME *gen;
                   1832:        int i, j;
                   1833:
                   1834:        for (i = 0; i < sk_GENERAL_NAMES_num(gns); i++) {
                   1835:                gens = sk_GENERAL_NAMES_value(gns, i);
                   1836:                for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) {
                   1837:                        gen = sk_GENERAL_NAME_value(gens, j);
                   1838:                        BIO_puts(out, "    ");
                   1839:                        GENERAL_NAME_print(out, gen);
                   1840:                        BIO_puts(out, "\n");
                   1841:                }
                   1842:        }
                   1843:        return;
                   1844: }
                   1845:
                   1846: static void
1.12      jsing    1847: receipt_request_print(BIO *out, CMS_ContentInfo *cms)
1.1       jsing    1848: {
1.12      jsing    1849:        STACK_OF(CMS_SignerInfo) *sis;
1.1       jsing    1850:        CMS_SignerInfo *si;
                   1851:        CMS_ReceiptRequest *rr;
                   1852:        int allorfirst;
1.12      jsing    1853:        STACK_OF(GENERAL_NAMES) *rto, *rlist;
1.1       jsing    1854:        ASN1_STRING *scid;
                   1855:        int i, rv;
                   1856:
1.17      inoguchi 1857:        if ((sis = CMS_get0_SignerInfos(cms)) == NULL)
                   1858:                return;
1.1       jsing    1859:        for (i = 0; i < sk_CMS_SignerInfo_num(sis); i++) {
1.23      inoguchi 1860:                if ((si = sk_CMS_SignerInfo_value(sis, i)) == NULL)
                   1861:                        return;
1.1       jsing    1862:                rv = CMS_get1_ReceiptRequest(si, &rr);
                   1863:                BIO_printf(bio_err, "Signer %d:\n", i + 1);
1.24      inoguchi 1864:                if (rv == 0) {
1.1       jsing    1865:                        BIO_puts(bio_err, "  No Receipt Request\n");
1.24      inoguchi 1866:                } else if (rv < 0) {
1.1       jsing    1867:                        BIO_puts(bio_err, "  Receipt Request Parse Error\n");
                   1868:                        ERR_print_errors(bio_err);
                   1869:                } else {
                   1870:                        char *id;
                   1871:                        int idlen;
1.24      inoguchi 1872:
1.1       jsing    1873:                        CMS_ReceiptRequest_get0_values(rr, &scid, &allorfirst,
                   1874:                            &rlist, &rto);
                   1875:                        BIO_puts(out, "  Signed Content ID:\n");
                   1876:                        idlen = ASN1_STRING_length(scid);
                   1877:                        id = (char *) ASN1_STRING_data(scid);
                   1878:                        BIO_dump_indent(out, id, idlen, 4);
                   1879:                        BIO_puts(out, "  Receipts From");
1.22      inoguchi 1880:                        if (rlist != NULL) {
1.1       jsing    1881:                                BIO_puts(out, " List:\n");
                   1882:                                gnames_stack_print(out, rlist);
1.24      inoguchi 1883:                        } else if (allorfirst == 1) {
1.1       jsing    1884:                                BIO_puts(out, ": First Tier\n");
1.24      inoguchi 1885:                        } else if (allorfirst == 0) {
1.1       jsing    1886:                                BIO_puts(out, ": All\n");
1.24      inoguchi 1887:                        } else {
1.1       jsing    1888:                                BIO_printf(out, " Unknown (%d)\n", allorfirst);
1.24      inoguchi 1889:                        }
1.1       jsing    1890:                        BIO_puts(out, "  Receipts To:\n");
                   1891:                        gnames_stack_print(out, rto);
                   1892:                }
1.25      inoguchi 1893:                CMS_ReceiptRequest_free(rr);
1.1       jsing    1894:        }
                   1895: }
                   1896:
                   1897: static STACK_OF(GENERAL_NAMES) *
1.12      jsing    1898: make_names_stack(STACK_OF(OPENSSL_STRING) *ns)
1.1       jsing    1899: {
                   1900:        int i;
1.12      jsing    1901:        STACK_OF(GENERAL_NAMES) *ret;
1.1       jsing    1902:        GENERAL_NAMES *gens = NULL;
                   1903:        GENERAL_NAME *gen = NULL;
1.22      inoguchi 1904:
1.16      inoguchi 1905:        if ((ret = sk_GENERAL_NAMES_new_null()) == NULL)
1.1       jsing    1906:                goto err;
                   1907:        for (i = 0; i < sk_OPENSSL_STRING_num(ns); i++) {
                   1908:                char *str = sk_OPENSSL_STRING_value(ns, i);
                   1909:                gen = a2i_GENERAL_NAME(NULL, NULL, NULL, GEN_EMAIL, str, 0);
1.22      inoguchi 1910:                if (gen == NULL)
1.1       jsing    1911:                        goto err;
                   1912:                gens = GENERAL_NAMES_new();
1.22      inoguchi 1913:                if (gens == NULL)
1.1       jsing    1914:                        goto err;
                   1915:                if (!sk_GENERAL_NAME_push(gens, gen))
                   1916:                        goto err;
                   1917:                gen = NULL;
                   1918:                if (!sk_GENERAL_NAMES_push(ret, gens))
                   1919:                        goto err;
                   1920:                gens = NULL;
                   1921:        }
                   1922:
                   1923:        return ret;
                   1924:
1.13      jsing    1925:  err:
1.11      jsing    1926:        sk_GENERAL_NAMES_pop_free(ret, GENERAL_NAMES_free);
                   1927:        GENERAL_NAMES_free(gens);
                   1928:        GENERAL_NAME_free(gen);
                   1929:
1.1       jsing    1930:        return NULL;
                   1931: }
                   1932:
                   1933:
                   1934: static CMS_ReceiptRequest *
1.12      jsing    1935: make_receipt_request(STACK_OF(OPENSSL_STRING) *rr_to, int rr_allorfirst,
                   1936:     STACK_OF(OPENSSL_STRING) *rr_from)
1.1       jsing    1937: {
1.26      inoguchi 1938:        STACK_OF(GENERAL_NAMES) *rct_to = NULL, *rct_from = NULL;
1.1       jsing    1939:        CMS_ReceiptRequest *rr;
                   1940:
                   1941:        rct_to = make_names_stack(rr_to);
1.22      inoguchi 1942:        if (rct_to == NULL)
1.1       jsing    1943:                goto err;
1.22      inoguchi 1944:        if (rr_from != NULL) {
1.1       jsing    1945:                rct_from = make_names_stack(rr_from);
1.22      inoguchi 1946:                if (rct_from == NULL)
1.1       jsing    1947:                        goto err;
1.24      inoguchi 1948:        } else {
1.1       jsing    1949:                rct_from = NULL;
1.24      inoguchi 1950:        }
1.17      inoguchi 1951:
                   1952:        if ((rr = CMS_ReceiptRequest_create0(NULL, -1, rr_allorfirst, rct_from,
                   1953:            rct_to)) == NULL)
                   1954:                goto err;
                   1955:
1.1       jsing    1956:        return rr;
                   1957:
1.13      jsing    1958:  err:
1.26      inoguchi 1959:        sk_GENERAL_NAMES_pop_free(rct_to, GENERAL_NAMES_free);
                   1960:        sk_GENERAL_NAMES_pop_free(rct_from, GENERAL_NAMES_free);
1.1       jsing    1961:        return NULL;
1.14      inoguchi 1962: }
                   1963:
                   1964: static int
                   1965: cms_set_pkey_param(EVP_PKEY_CTX *pctx, STACK_OF(OPENSSL_STRING) *param)
                   1966: {
                   1967:        char *keyopt;
                   1968:        int i;
1.15      inoguchi 1969:
1.14      inoguchi 1970:        if (sk_OPENSSL_STRING_num(param) <= 0)
                   1971:                return 1;
                   1972:        for (i = 0; i < sk_OPENSSL_STRING_num(param); i++) {
                   1973:                keyopt = sk_OPENSSL_STRING_value(param, i);
                   1974:                if (pkey_ctrl_string(pctx, keyopt) <= 0) {
                   1975:                        BIO_printf(bio_err, "parameter error \"%s\"\n", keyopt);
                   1976:                        ERR_print_errors(bio_err);
                   1977:                        return 0;
                   1978:                }
                   1979:        }
                   1980:        return 1;
1.1       jsing    1981: }
                   1982:
                   1983: #endif