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

Annotation of src/usr.bin/openssl/smime.c, Revision 1.12

1.12    ! inoguchi    1: /* $OpenBSD: smime.c,v 1.11 2022/01/11 14:23:05 inoguchi Exp $ */
1.1       jsing       2: /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
                      3:  * project.
                      4:  */
                      5: /* ====================================================================
                      6:  * Copyright (c) 1999-2004 The OpenSSL Project.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  *
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  *
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in
                     17:  *    the documentation and/or other materials provided with the
                     18:  *    distribution.
                     19:  *
                     20:  * 3. All advertising materials mentioning features or use of this
                     21:  *    software must display the following acknowledgment:
                     22:  *    "This product includes software developed by the OpenSSL Project
                     23:  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
                     24:  *
                     25:  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
                     26:  *    endorse or promote products derived from this software without
                     27:  *    prior written permission. For written permission, please contact
                     28:  *    licensing@OpenSSL.org.
                     29:  *
                     30:  * 5. Products derived from this software may not be called "OpenSSL"
                     31:  *    nor may "OpenSSL" appear in their names without prior written
                     32:  *    permission of the OpenSSL Project.
                     33:  *
                     34:  * 6. Redistributions of any form whatsoever must retain the following
                     35:  *    acknowledgment:
                     36:  *    "This product includes software developed by the OpenSSL Project
                     37:  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
                     38:  *
                     39:  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
                     40:  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     41:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     42:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
                     43:  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     44:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     45:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     46:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     47:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     48:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     49:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
                     50:  * OF THE POSSIBILITY OF SUCH DAMAGE.
                     51:  * ====================================================================
                     52:  *
                     53:  * This product includes cryptographic software written by Eric Young
                     54:  * (eay@cryptsoft.com).  This product includes software written by Tim
                     55:  * Hudson (tjh@cryptsoft.com).
                     56:  *
                     57:  */
                     58:
                     59: /* S/MIME utility function */
                     60:
                     61: #include <stdio.h>
                     62: #include <string.h>
                     63:
                     64: #include "apps.h"
                     65:
                     66: #include <openssl/crypto.h>
                     67: #include <openssl/err.h>
                     68: #include <openssl/pem.h>
                     69: #include <openssl/x509_vfy.h>
                     70: #include <openssl/x509v3.h>
                     71:
1.12    ! inoguchi   72: static int save_certs(char *signerfile, STACK_OF(X509) *signers);
        !            73: static int smime_cb(int ok, X509_STORE_CTX *ctx);
1.1       jsing      74:
                     75: #define SMIME_OP       0x10
                     76: #define SMIME_IP       0x20
                     77: #define SMIME_SIGNERS  0x40
                     78: #define SMIME_ENCRYPT  (1 | SMIME_OP)
                     79: #define SMIME_DECRYPT  (2 | SMIME_IP)
                     80: #define SMIME_SIGN     (3 | SMIME_OP | SMIME_SIGNERS)
                     81: #define SMIME_VERIFY   (4 | SMIME_IP)
                     82: #define SMIME_PK7OUT   (5 | SMIME_IP | SMIME_OP)
                     83: #define SMIME_RESIGN   (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
                     84:
1.11      inoguchi   85: static struct {
                     86:        char *CAfile;
                     87:        char *CApath;
                     88:        char *certfile;
                     89:        const EVP_CIPHER *cipher;
                     90:        char *contfile;
                     91:        int flags;
                     92:        char *from;
                     93:        int indef;
                     94:        char *infile;
                     95:        int informat;
                     96:        char *keyfile;
                     97:        int keyform;
                     98:        int operation;
                     99:        char *outfile;
                    100:        int outformat;
                    101:        char *passargin;
                    102:        char *recipfile;
                    103:        const EVP_MD *sign_md;
                    104:        char *signerfile;
                    105:        STACK_OF(OPENSSL_STRING) *skkeys;
                    106:        STACK_OF(OPENSSL_STRING) *sksigners;
                    107:        char *subject;
                    108:        char *to;
                    109:        X509_VERIFY_PARAM *vpm;
                    110: } smime_config;
                    111:
                    112: static const EVP_CIPHER *
                    113: get_cipher_by_name(char *name)
                    114: {
                    115:        if (name == NULL || strcmp(name, "") == 0)
                    116:                return (NULL);
                    117: #ifndef OPENSSL_NO_AES
                    118:        else if (strcmp(name, "aes128") == 0)
                    119:                return EVP_aes_128_cbc();
                    120:        else if (strcmp(name, "aes192") == 0)
                    121:                return EVP_aes_192_cbc();
                    122:        else if (strcmp(name, "aes256") == 0)
                    123:                return EVP_aes_256_cbc();
                    124: #endif
                    125: #ifndef OPENSSL_NO_CAMELLIA
                    126:        else if (strcmp(name, "camellia128") == 0)
                    127:                return EVP_camellia_128_cbc();
                    128:        else if (strcmp(name, "camellia192") == 0)
                    129:                return EVP_camellia_192_cbc();
                    130:        else if (strcmp(name, "camellia256") == 0)
                    131:                return EVP_camellia_256_cbc();
                    132: #endif
                    133: #ifndef OPENSSL_NO_DES
                    134:        else if (strcmp(name, "des") == 0)
                    135:                return EVP_des_cbc();
                    136:        else if (strcmp(name, "des3") == 0)
                    137:                return EVP_des_ede3_cbc();
                    138: #endif
                    139: #ifndef OPENSSL_NO_RC2
                    140:        else if (!strcmp(name, "rc2-40"))
                    141:                return EVP_rc2_40_cbc();
                    142:        else if (!strcmp(name, "rc2-64"))
                    143:                return EVP_rc2_64_cbc();
                    144:        else if (!strcmp(name, "rc2-128"))
                    145:                return EVP_rc2_cbc();
                    146: #endif
                    147: }
                    148:
                    149: static int
                    150: smime_opt_cipher(int argc, char **argv, int *argsused)
                    151: {
                    152:        char *name = argv[0];
                    153:
                    154:        if (*name++ != '-')
                    155:                return (1);
                    156:
                    157:        if ((smime_config.cipher = get_cipher_by_name(name)) == NULL)
                    158:                if ((smime_config.cipher = EVP_get_cipherbyname(name)) == NULL)
                    159:                        return (1);
                    160:
                    161:        *argsused = 1;
                    162:        return (0);
                    163: }
                    164:
                    165: static int
                    166: smime_opt_inkey(char *arg)
                    167: {
                    168:        if (smime_config.keyfile == NULL) {
                    169:                smime_config.keyfile = arg;
                    170:                return (0);
                    171:        }
                    172:
                    173:        if (smime_config.signerfile == NULL) {
                    174:                BIO_puts(bio_err, "Illegal -inkey without -signer\n");
                    175:                return (1);
                    176:        }
                    177:
                    178:        if (smime_config.sksigners == NULL) {
                    179:                if ((smime_config.sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
                    180:                        return (1);
                    181:        }
                    182:        if (!sk_OPENSSL_STRING_push(smime_config.sksigners,
                    183:            smime_config.signerfile))
                    184:                return (1);
                    185:
                    186:        smime_config.signerfile = NULL;
                    187:
                    188:        if (smime_config.skkeys == NULL) {
                    189:                if ((smime_config.skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
                    190:                        return (1);
                    191:        }
                    192:        if (!sk_OPENSSL_STRING_push(smime_config.skkeys, smime_config.keyfile))
                    193:                return (1);
                    194:
                    195:        smime_config.keyfile = arg;
                    196:        return (0);
                    197: }
                    198:
                    199: static int
                    200: smime_opt_md(char *arg)
                    201: {
                    202:        if ((smime_config.sign_md = EVP_get_digestbyname(arg)) == NULL) {
                    203:                BIO_printf(bio_err, "Unknown digest %s\n", arg);
                    204:                return (1);
                    205:        }
                    206:        return (0);
                    207: }
                    208:
                    209: static int
                    210: smime_opt_signer(char *arg)
                    211: {
                    212:        if (smime_config.signerfile == NULL) {
                    213:                smime_config.signerfile = arg;
                    214:                return (0);
                    215:        }
                    216:
                    217:        if (smime_config.sksigners == NULL) {
                    218:                if ((smime_config.sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
                    219:                        return (1);
                    220:        }
                    221:        if (!sk_OPENSSL_STRING_push(smime_config.sksigners,
                    222:            smime_config.signerfile))
                    223:                return (1);
                    224:
                    225:        if (smime_config.keyfile == NULL)
                    226:                smime_config.keyfile = smime_config.signerfile;
                    227:
                    228:        if (smime_config.skkeys == NULL) {
                    229:                if ((smime_config.skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
                    230:                        return (1);
                    231:        }
                    232:        if (!sk_OPENSSL_STRING_push(smime_config.skkeys, smime_config.keyfile))
                    233:                return (1);
                    234:
                    235:        smime_config.keyfile = NULL;
                    236:
                    237:        smime_config.signerfile = arg;
                    238:        return (0);
                    239: }
                    240:
                    241: static int
                    242: smime_opt_verify_param(int argc, char **argv, int *argsused)
                    243: {
                    244:        int oargc = argc;
                    245:        int badarg = 0;
                    246:
                    247:        if (!args_verify(&argv, &argc, &badarg, bio_err, &smime_config.vpm))
                    248:                return (1);
                    249:        if (badarg)
                    250:                return (1);
                    251:
                    252:        *argsused = oargc - argc;
                    253:
                    254:        return (0);
                    255: }
                    256:
                    257: static const struct option smime_options[] = {
                    258: #ifndef OPENSSL_NO_AES
                    259:        {
                    260:                .name = "aes128",
                    261:                .desc = "Encrypt PEM output with CBC AES",
                    262:                .type = OPTION_ARGV_FUNC,
                    263:                .opt.argvfunc = smime_opt_cipher,
                    264:        },
                    265:        {
                    266:                .name = "aes192",
                    267:                .desc = "Encrypt PEM output with CBC AES",
                    268:                .type = OPTION_ARGV_FUNC,
                    269:                .opt.argvfunc = smime_opt_cipher,
                    270:        },
                    271:        {
                    272:                .name = "aes256",
                    273:                .desc = "Encrypt PEM output with CBC AES",
                    274:                .type = OPTION_ARGV_FUNC,
                    275:                .opt.argvfunc = smime_opt_cipher,
                    276:        },
                    277: #endif
                    278: #ifndef OPENSSL_NO_CAMELLIA
                    279:        {
                    280:                .name = "camellia128",
                    281:                .desc = "Encrypt PEM output with CBC Camellia",
                    282:                .type = OPTION_ARGV_FUNC,
                    283:                .opt.argvfunc = smime_opt_cipher,
                    284:        },
                    285:        {
                    286:                .name = "camellia192",
                    287:                .desc = "Encrypt PEM output with CBC Camellia",
                    288:                .type = OPTION_ARGV_FUNC,
                    289:                .opt.argvfunc = smime_opt_cipher,
                    290:        },
                    291:        {
                    292:                .name = "camellia256",
                    293:                .desc = "Encrypt PEM output with CBC Camellia",
                    294:                .type = OPTION_ARGV_FUNC,
                    295:                .opt.argvfunc = smime_opt_cipher,
                    296:        },
                    297: #endif
                    298: #ifndef OPENSSL_NO_DES
                    299:        {
                    300:                .name = "des",
                    301:                .desc = "Encrypt with DES",
                    302:                .type = OPTION_ARGV_FUNC,
                    303:                .opt.argvfunc = smime_opt_cipher,
                    304:        },
                    305:        {
                    306:                .name = "des3",
                    307:                .desc = "Encrypt with triple DES",
                    308:                .type = OPTION_ARGV_FUNC,
                    309:                .opt.argvfunc = smime_opt_cipher,
                    310:        },
                    311: #endif
                    312: #ifndef OPENSSL_NO_RC2
                    313:        {
                    314:                .name = "rc2-40",
                    315:                .desc = "Encrypt with RC2-40 (default)",
                    316:                .type = OPTION_ARGV_FUNC,
                    317:                .opt.argvfunc = smime_opt_cipher,
                    318:        },
                    319:        {
                    320:                .name = "rc2-64",
                    321:                .desc = "Encrypt with RC2-64",
                    322:                .type = OPTION_ARGV_FUNC,
                    323:                .opt.argvfunc = smime_opt_cipher,
                    324:        },
                    325:        {
                    326:                .name = "rc2-128",
                    327:                .desc = "Encrypt with RC2-128",
                    328:                .type = OPTION_ARGV_FUNC,
                    329:                .opt.argvfunc = smime_opt_cipher,
                    330:        },
                    331: #endif
                    332:        {
                    333:                .name = "CAfile",
                    334:                .argname = "file",
                    335:                .desc = "Certificate Authority file",
                    336:                .type = OPTION_ARG,
                    337:                .opt.arg = &smime_config.CAfile,
                    338:        },
                    339:        {
                    340:                .name = "CApath",
                    341:                .argname = "path",
                    342:                .desc = "Certificate Authority path",
                    343:                .type = OPTION_ARG,
                    344:                .opt.arg = &smime_config.CApath,
                    345:        },
                    346:        {
                    347:                .name = "binary",
                    348:                .desc = "Do not translate message to text",
                    349:                .type = OPTION_VALUE_OR,
                    350:                .opt.value = &smime_config.flags,
                    351:                .value = PKCS7_BINARY,
                    352:        },
                    353:        {
                    354:                .name = "certfile",
                    355:                .argname = "file",
                    356:                .desc = "Other certificates file",
                    357:                .type = OPTION_ARG,
                    358:                .opt.arg = &smime_config.certfile,
                    359:        },
                    360:        {
                    361:                .name = "content",
                    362:                .argname = "file",
                    363:                .desc = "Supply or override content for detached signature",
                    364:                .type = OPTION_ARG,
                    365:                .opt.arg = &smime_config.contfile,
                    366:        },
                    367:        {
                    368:                .name = "crlfeol",
                    369:                .desc = "Use CRLF as EOL termination instead of CR only",
                    370:                .type = OPTION_VALUE_OR,
                    371:                .opt.value = &smime_config.flags,
                    372:                .value = PKCS7_CRLFEOL,
                    373:        },
                    374:        {
                    375:                .name = "decrypt",
                    376:                .desc = "Decrypt encrypted message",
                    377:                .type = OPTION_VALUE,
                    378:                .opt.value = &smime_config.operation,
                    379:                .value = SMIME_DECRYPT,
                    380:        },
                    381:        {
                    382:                .name = "encrypt",
                    383:                .desc = "Encrypt message",
                    384:                .type = OPTION_VALUE,
                    385:                .opt.value = &smime_config.operation,
                    386:                .value = SMIME_ENCRYPT,
                    387:        },
                    388:        {
                    389:                .name = "from",
                    390:                .argname = "addr",
                    391:                .desc = "From address",
                    392:                .type = OPTION_ARG,
                    393:                .opt.arg = &smime_config.from,
                    394:        },
                    395:        {
                    396:                .name = "in",
                    397:                .argname = "file",
                    398:                .desc = "Input file",
                    399:                .type = OPTION_ARG,
                    400:                .opt.arg = &smime_config.infile,
                    401:        },
                    402:        {
                    403:                .name = "indef",
                    404:                .desc = "Same as -stream",
                    405:                .type = OPTION_VALUE,
                    406:                .opt.value = &smime_config.indef,
                    407:                .value = 1,
                    408:        },
                    409:        {
                    410:                .name = "inform",
                    411:                .argname = "fmt",
                    412:                .desc = "Input format (DER, PEM or SMIME (default))",
                    413:                .type = OPTION_ARG_FORMAT,
                    414:                .opt.value = &smime_config.informat,
                    415:        },
                    416:        {
                    417:                .name = "inkey",
                    418:                .argname = "file",
                    419:                .desc = "Input key file",
                    420:                .type = OPTION_ARG_FUNC,
                    421:                .opt.argfunc = smime_opt_inkey,
                    422:        },
                    423:        {
                    424:                .name = "keyform",
                    425:                .argname = "fmt",
                    426:                .desc = "Input key format (DER or PEM (default))",
                    427:                .type = OPTION_ARG_FORMAT,
                    428:                .opt.value = &smime_config.keyform,
                    429:        },
                    430:        {
                    431:                .name = "md",
                    432:                .argname = "digest",
                    433:                .desc = "Digest to use when signing or resigning",
                    434:                .type = OPTION_ARG_FUNC,
                    435:                .opt.argfunc = smime_opt_md,
                    436:        },
                    437:        {
                    438:                .name = "noattr",
                    439:                .desc = "Do not include any signed attributes",
                    440:                .type = OPTION_VALUE_OR,
                    441:                .opt.value = &smime_config.flags,
                    442:                .value = PKCS7_NOATTR,
                    443:        },
                    444:        {
                    445:                .name = "nocerts",
                    446:                .desc = "Do not include signer's certificate when signing",
                    447:                .type = OPTION_VALUE_OR,
                    448:                .opt.value = &smime_config.flags,
                    449:                .value = PKCS7_NOCERTS,
                    450:        },
                    451:        {
                    452:                .name = "nochain",
                    453:                .desc = "Do not chain verification of signer's certificates",
                    454:                .type = OPTION_VALUE_OR,
                    455:                .opt.value = &smime_config.flags,
                    456:                .value = PKCS7_NOCHAIN,
                    457:        },
                    458:        {
                    459:                .name = "nodetach",
                    460:                .desc = "Use opaque signing",
                    461:                .type = OPTION_VALUE_AND,
                    462:                .opt.value = &smime_config.flags,
                    463:                .value = ~PKCS7_DETACHED,
                    464:        },
                    465:        {
                    466:                .name = "noindef",
                    467:                .desc = "Disable streaming I/O",
                    468:                .type = OPTION_VALUE,
                    469:                .opt.value = &smime_config.indef,
                    470:                .value = 0,
                    471:        },
                    472:        {
                    473:                .name = "nointern",
                    474:                .desc = "Do not search certificates in message for signer",
                    475:                .type = OPTION_VALUE_OR,
                    476:                .opt.value = &smime_config.flags,
                    477:                .value = PKCS7_NOINTERN,
                    478:        },
                    479:        {
                    480:                .name = "nooldmime",
                    481:                .desc = "Output old S/MIME content type",
                    482:                .type = OPTION_VALUE_OR,
                    483:                .opt.value = &smime_config.flags,
                    484:                .value = PKCS7_NOOLDMIMETYPE,
                    485:        },
                    486:        {
                    487:                .name = "nosigs",
                    488:                .desc = "Do not verify message signature",
                    489:                .type = OPTION_VALUE_OR,
                    490:                .opt.value = &smime_config.flags,
                    491:                .value = PKCS7_NOSIGS,
                    492:        },
                    493:        {
                    494:                .name = "nosmimecap",
                    495:                .desc = "Omit the SMIMECapabilities attribute",
                    496:                .type = OPTION_VALUE_OR,
                    497:                .opt.value = &smime_config.flags,
                    498:                .value = PKCS7_NOSMIMECAP,
                    499:        },
                    500:        {
                    501:                .name = "noverify",
                    502:                .desc = "Do not verify signer's certificate",
                    503:                .type = OPTION_VALUE_OR,
                    504:                .opt.value = &smime_config.flags,
                    505:                .value = PKCS7_NOVERIFY,
                    506:        },
                    507:        {
                    508:                .name = "out",
                    509:                .argname = "file",
                    510:                .desc = "Output file",
                    511:                .type = OPTION_ARG,
                    512:                .opt.arg = &smime_config.outfile,
                    513:        },
                    514:        {
                    515:                .name = "outform",
                    516:                .argname = "fmt",
                    517:                .desc = "Output format (DER, PEM or SMIME (default))",
                    518:                .type = OPTION_ARG_FORMAT,
                    519:                .opt.value = &smime_config.outformat,
                    520:        },
                    521:        {
                    522:                .name = "passin",
                    523:                .argname = "src",
                    524:                .desc = "Private key password source",
                    525:                .type = OPTION_ARG,
                    526:                .opt.arg = &smime_config.passargin,
                    527:        },
                    528:        {
                    529:                .name = "pk7out",
                    530:                .desc = "Output PKCS#7 structure",
                    531:                .type = OPTION_VALUE,
                    532:                .opt.value = &smime_config.operation,
                    533:                .value = SMIME_PK7OUT,
                    534:        },
                    535:        {
                    536:                .name = "recip",
                    537:                .argname = "file",
                    538:                .desc = "Recipient certificate file for decryption",
                    539:                .type = OPTION_ARG,
                    540:                .opt.arg = &smime_config.recipfile,
                    541:        },
                    542:        {
                    543:                .name = "resign",
                    544:                .desc = "Resign a signed message",
                    545:                .type = OPTION_VALUE,
                    546:                .opt.value = &smime_config.operation,
                    547:                .value = SMIME_RESIGN,
                    548:        },
                    549:        {
                    550:                .name = "sign",
                    551:                .desc = "Sign message",
                    552:                .type = OPTION_VALUE,
                    553:                .opt.value = &smime_config.operation,
                    554:                .value = SMIME_SIGN,
                    555:        },
                    556:        {
                    557:                .name = "signer",
                    558:                .argname = "file",
                    559:                .desc = "Signer certificate file",
                    560:                .type = OPTION_ARG_FUNC,
                    561:                .opt.argfunc = smime_opt_signer,
                    562:        },
                    563:        {
                    564:                .name = "stream",
                    565:                .desc = "Enable streaming I/O",
                    566:                .type = OPTION_VALUE,
                    567:                .opt.value = &smime_config.indef,
                    568:                .value = 1,
                    569:        },
                    570:        {
                    571:                .name = "subject",
                    572:                .argname = "s",
                    573:                .desc = "Subject",
                    574:                .type = OPTION_ARG,
                    575:                .opt.arg = &smime_config.subject,
                    576:        },
                    577:        {
                    578:                .name = "text",
                    579:                .desc = "Include or delete text MIME headers",
                    580:                .type = OPTION_VALUE_OR,
                    581:                .opt.value = &smime_config.flags,
                    582:                .value = PKCS7_TEXT,
                    583:        },
                    584:        {
                    585:                .name = "to",
                    586:                .argname = "addr",
                    587:                .desc = "To address",
                    588:                .type = OPTION_ARG,
                    589:                .opt.arg = &smime_config.to,
                    590:        },
                    591:        {
                    592:                .name = "verify",
                    593:                .desc = "Verify signed message",
                    594:                .type = OPTION_VALUE,
                    595:                .opt.value = &smime_config.operation,
                    596:                .value = SMIME_VERIFY,
                    597:        },
                    598:        {
                    599:                .name = "check_ss_sig",
                    600:                .type = OPTION_ARGV_FUNC,
                    601:                .opt.argvfunc = smime_opt_verify_param,
                    602:        },
                    603:        {
                    604:                .name = "crl_check",
                    605:                .type = OPTION_ARGV_FUNC,
                    606:                .opt.argvfunc = smime_opt_verify_param,
                    607:        },
                    608:        {
                    609:                .name = "crl_check_all",
                    610:                .type = OPTION_ARGV_FUNC,
                    611:                .opt.argvfunc = smime_opt_verify_param,
                    612:        },
                    613:        {
                    614:                .name = "extended_crl",
                    615:                .type = OPTION_ARGV_FUNC,
                    616:                .opt.argvfunc = smime_opt_verify_param,
                    617:        },
                    618:        {
                    619:                .name = "ignore_critical",
                    620:                .type = OPTION_ARGV_FUNC,
                    621:                .opt.argvfunc = smime_opt_verify_param,
                    622:        },
                    623:        {
                    624:                .name = "issuer_checks",
                    625:                .type = OPTION_ARGV_FUNC,
                    626:                .opt.argvfunc = smime_opt_verify_param,
                    627:        },
                    628:        {
                    629:                .name = "policy_check",
                    630:                .type = OPTION_ARGV_FUNC,
                    631:                .opt.argvfunc = smime_opt_verify_param,
                    632:        },
                    633:        {
                    634:                .name = "x509_strict",
                    635:                .type = OPTION_ARGV_FUNC,
                    636:                .opt.argvfunc = smime_opt_verify_param,
                    637:        },
                    638:        {
                    639:                .name = NULL,
                    640:                .type = OPTION_ARGV_FUNC,
                    641:                .opt.argvfunc = smime_opt_cipher,
                    642:        },
                    643:        { NULL },
                    644: };
                    645:
                    646: static const struct option verify_shared_options[] = {
                    647:        {
                    648:                .name = "check_ss_sig",
                    649:                .desc = "Check the root CA self-signed certificate signature",
                    650:        },
                    651:        {
                    652:                .name = "crl_check",
                    653:                .desc = "Enable CRL checking for the leaf certificate",
                    654:        },
                    655:        {
                    656:                .name = "crl_check_all",
                    657:                .desc = "Enable CRL checking for the entire certificate chain",
                    658:        },
                    659:        {
                    660:                .name = "extended_crl",
                    661:                .desc = "Enable extended CRL support",
                    662:        },
                    663:        {
                    664:                .name = "ignore_critical",
                    665:                .desc = "Disable critical extension checking",
                    666:        },
                    667:        {
                    668:                .name = "issuer_checks",
                    669:                .desc = "Enable debugging of certificate issuer checks",
                    670:        },
                    671:        {
                    672:                .name = "policy_check",
                    673:                .desc = "Enable certificate policy checking",
                    674:        },
                    675:        {
                    676:                .name = "x509_strict",
                    677:                .desc = "Use strict X.509 rules (disables workarounds)",
                    678:        },
                    679:        { NULL },
                    680: };
                    681:
                    682: static void
                    683: smime_usage(void)
                    684: {
                    685:        fprintf(stderr, "usage: smime "
                    686:            "[-aes128 | -aes192 | -aes256 | -des |\n"
                    687:            "    -des3 | -rc2-40 | -rc2-64 | -rc2-128] [-binary]\n"
                    688:            "    [-CAfile file] [-CApath directory] [-certfile file]\n"
                    689:            "    [-content file]\n"
                    690:            "    [-decrypt] [-encrypt]\n"
                    691:            "    [-from addr] [-in file] [-indef]\n"
                    692:            "    [-inform der | pem | smime] [-inkey file]\n"
                    693:            "    [-keyform der | pem] [-md digest] [-noattr] [-nocerts]\n"
                    694:            "    [-nochain] [-nodetach] [-noindef] [-nointern] [-nosigs]\n"
                    695:            "    [-nosmimecap] [-noverify] [-out file]\n"
                    696:            "    [-outform der | pem | smime] [-passin arg] [-pk7out]\n"
                    697:            "    [-recip file] [-resign] [-sign]\n"
                    698:            "    [-signer file] [-stream] [-subject s] [-text] [-to addr]\n"
                    699:            "    [-verify] [cert.pem ...]\n\n");
                    700:
                    701:        options_usage(smime_options);
                    702:
                    703:        fprintf(stderr, "\nVerification options:\n\n");
                    704:        options_usage(verify_shared_options);
                    705: }
                    706:
1.1       jsing     707: int
                    708: smime_main(int argc, char **argv)
                    709: {
                    710:        int ret = 0;
                    711:        char **args;
1.11      inoguchi  712:        int argsused = 0;
1.1       jsing     713:        const char *inmode = "r", *outmode = "w";
                    714:        PKCS7 *p7 = NULL;
                    715:        X509_STORE *store = NULL;
                    716:        X509 *cert = NULL, *recip = NULL, *signer = NULL;
                    717:        EVP_PKEY *key = NULL;
1.12    ! inoguchi  718:        STACK_OF(X509) *encerts = NULL, *other = NULL;
1.1       jsing     719:        BIO *in = NULL, *out = NULL, *indata = NULL;
                    720:        int badarg = 0;
1.11      inoguchi  721:        char *passin = NULL;
1.5       doug      722:
                    723:        if (single_execution) {
1.8       deraadt   724:                if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
1.5       doug      725:                        perror("pledge");
1.7       doug      726:                        exit(1);
                    727:                }
1.5       doug      728:        }
1.1       jsing     729:
1.11      inoguchi  730:        memset(&smime_config, 0, sizeof(smime_config));
                    731:        smime_config.flags = PKCS7_DETACHED;
                    732:        smime_config.informat = FORMAT_SMIME;
                    733:        smime_config.outformat = FORMAT_SMIME;
                    734:        smime_config.keyform = FORMAT_PEM;
                    735:        if (options_parse(argc, argv, smime_options, NULL, &argsused) != 0) {
                    736:                goto argerr;
                    737:        }
                    738:        args = argv + argsused;
1.1       jsing     739:        ret = 1;
                    740:
1.11      inoguchi  741:        if (!(smime_config.operation & SMIME_SIGNERS) && (smime_config.skkeys || smime_config.sksigners)) {
1.1       jsing     742:                BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
                    743:                goto argerr;
                    744:        }
1.11      inoguchi  745:        if (smime_config.operation & SMIME_SIGNERS) {
1.1       jsing     746:                /* Check to see if any final signer needs to be appended */
1.11      inoguchi  747:                if (smime_config.keyfile && !smime_config.signerfile) {
1.1       jsing     748:                        BIO_puts(bio_err, "Illegal -inkey without -signer\n");
                    749:                        goto argerr;
                    750:                }
1.11      inoguchi  751:                if (smime_config.signerfile) {
                    752:                        if (!smime_config.sksigners)
                    753:                                smime_config.sksigners = sk_OPENSSL_STRING_new_null();
                    754:                        sk_OPENSSL_STRING_push(smime_config.sksigners, smime_config.signerfile);
                    755:                        if (!smime_config.skkeys)
                    756:                                smime_config.skkeys = sk_OPENSSL_STRING_new_null();
                    757:                        if (!smime_config.keyfile)
                    758:                                smime_config.keyfile = smime_config.signerfile;
                    759:                        sk_OPENSSL_STRING_push(smime_config.skkeys, smime_config.keyfile);
1.1       jsing     760:                }
1.11      inoguchi  761:                if (!smime_config.sksigners) {
1.1       jsing     762:                        BIO_printf(bio_err, "No signer certificate specified\n");
                    763:                        badarg = 1;
                    764:                }
1.11      inoguchi  765:                smime_config.signerfile = NULL;
                    766:                smime_config.keyfile = NULL;
                    767:        } else if (smime_config.operation == SMIME_DECRYPT) {
                    768:                if (!smime_config.recipfile && !smime_config.keyfile) {
1.1       jsing     769:                        BIO_printf(bio_err, "No recipient certificate or key specified\n");
                    770:                        badarg = 1;
                    771:                }
1.11      inoguchi  772:        } else if (smime_config.operation == SMIME_ENCRYPT) {
1.1       jsing     773:                if (!*args) {
                    774:                        BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
                    775:                        badarg = 1;
                    776:                }
1.11      inoguchi  777:        } else if (!smime_config.operation)
1.1       jsing     778:                badarg = 1;
                    779:
                    780:        if (badarg) {
1.10      jsing     781:  argerr:
1.11      inoguchi  782:                smime_usage();
1.1       jsing     783:                goto end;
                    784:        }
                    785:
1.11      inoguchi  786:        if (!app_passwd(bio_err, smime_config.passargin, NULL, &passin, NULL)) {
1.1       jsing     787:                BIO_printf(bio_err, "Error getting password\n");
                    788:                goto end;
                    789:        }
                    790:        ret = 2;
                    791:
1.11      inoguchi  792:        if (!(smime_config.operation & SMIME_SIGNERS))
                    793:                smime_config.flags &= ~PKCS7_DETACHED;
1.1       jsing     794:
1.11      inoguchi  795:        if (smime_config.operation & SMIME_OP) {
                    796:                if (smime_config.outformat == FORMAT_ASN1)
1.1       jsing     797:                        outmode = "wb";
                    798:        } else {
1.11      inoguchi  799:                if (smime_config.flags & PKCS7_BINARY)
1.1       jsing     800:                        outmode = "wb";
                    801:        }
                    802:
1.11      inoguchi  803:        if (smime_config.operation & SMIME_IP) {
                    804:                if (smime_config.informat == FORMAT_ASN1)
1.1       jsing     805:                        inmode = "rb";
                    806:        } else {
1.11      inoguchi  807:                if (smime_config.flags & PKCS7_BINARY)
1.1       jsing     808:                        inmode = "rb";
                    809:        }
                    810:
1.11      inoguchi  811:        if (smime_config.operation == SMIME_ENCRYPT) {
                    812:                if (!smime_config.cipher) {
1.1       jsing     813: #ifndef OPENSSL_NO_RC2
1.11      inoguchi  814:                        smime_config.cipher = EVP_rc2_40_cbc();
1.1       jsing     815: #else
                    816:                        BIO_printf(bio_err, "No cipher selected\n");
                    817:                        goto end;
                    818: #endif
                    819:                }
                    820:                encerts = sk_X509_new_null();
                    821:                while (*args) {
                    822:                        if (!(cert = load_cert(bio_err, *args, FORMAT_PEM,
1.4       bcook     823:                            NULL, "recipient certificate file"))) {
1.1       jsing     824:                                goto end;
                    825:                        }
                    826:                        sk_X509_push(encerts, cert);
                    827:                        cert = NULL;
                    828:                        args++;
                    829:                }
                    830:        }
1.11      inoguchi  831:        if (smime_config.certfile) {
                    832:                if (!(other = load_certs(bio_err, smime_config.certfile, FORMAT_PEM, NULL,
1.4       bcook     833:                    "certificate file"))) {
1.1       jsing     834:                        ERR_print_errors(bio_err);
                    835:                        goto end;
                    836:                }
                    837:        }
1.11      inoguchi  838:        if (smime_config.recipfile && (smime_config.operation == SMIME_DECRYPT)) {
                    839:                if (!(recip = load_cert(bio_err, smime_config.recipfile, FORMAT_PEM, NULL,
1.4       bcook     840:                    "recipient certificate file"))) {
1.1       jsing     841:                        ERR_print_errors(bio_err);
                    842:                        goto end;
                    843:                }
                    844:        }
1.11      inoguchi  845:        if (smime_config.operation == SMIME_DECRYPT) {
                    846:                if (!smime_config.keyfile)
                    847:                        smime_config.keyfile = smime_config.recipfile;
                    848:        } else if (smime_config.operation == SMIME_SIGN) {
                    849:                if (!smime_config.keyfile)
                    850:                        smime_config.keyfile = smime_config.signerfile;
1.1       jsing     851:        } else
1.11      inoguchi  852:                smime_config.keyfile = NULL;
1.1       jsing     853:
1.11      inoguchi  854:        if (smime_config.keyfile) {
                    855:                key = load_key(bio_err, smime_config.keyfile, smime_config.keyform, 0, passin,
1.1       jsing     856:                    "signing key file");
                    857:                if (!key)
                    858:                        goto end;
                    859:        }
1.11      inoguchi  860:        if (smime_config.infile) {
                    861:                if (!(in = BIO_new_file(smime_config.infile, inmode))) {
1.1       jsing     862:                        BIO_printf(bio_err,
1.11      inoguchi  863:                            "Can't open input file %s\n", smime_config.infile);
1.1       jsing     864:                        goto end;
                    865:                }
                    866:        } else
                    867:                in = BIO_new_fp(stdin, BIO_NOCLOSE);
                    868:
1.11      inoguchi  869:        if (smime_config.operation & SMIME_IP) {
                    870:                if (smime_config.informat == FORMAT_SMIME)
1.1       jsing     871:                        p7 = SMIME_read_PKCS7(in, &indata);
1.11      inoguchi  872:                else if (smime_config.informat == FORMAT_PEM)
1.1       jsing     873:                        p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
1.11      inoguchi  874:                else if (smime_config.informat == FORMAT_ASN1)
1.1       jsing     875:                        p7 = d2i_PKCS7_bio(in, NULL);
                    876:                else {
                    877:                        BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
                    878:                        goto end;
                    879:                }
                    880:
                    881:                if (!p7) {
                    882:                        BIO_printf(bio_err, "Error reading S/MIME message\n");
                    883:                        goto end;
                    884:                }
1.11      inoguchi  885:                if (smime_config.contfile) {
1.1       jsing     886:                        BIO_free(indata);
1.11      inoguchi  887:                        if (!(indata = BIO_new_file(smime_config.contfile, "rb"))) {
                    888:                                BIO_printf(bio_err, "Can't read content file %s\n", smime_config.contfile);
1.1       jsing     889:                                goto end;
                    890:                        }
                    891:                }
                    892:        }
1.11      inoguchi  893:        if (smime_config.outfile) {
                    894:                if (!(out = BIO_new_file(smime_config.outfile, outmode))) {
1.1       jsing     895:                        BIO_printf(bio_err,
1.11      inoguchi  896:                            "Can't open output file %s\n", smime_config.outfile);
1.1       jsing     897:                        goto end;
                    898:                }
                    899:        } else {
                    900:                out = BIO_new_fp(stdout, BIO_NOCLOSE);
                    901:        }
                    902:
1.11      inoguchi  903:        if (smime_config.operation == SMIME_VERIFY) {
                    904:                if (!(store = setup_verify(bio_err, smime_config.CAfile, smime_config.CApath)))
1.1       jsing     905:                        goto end;
                    906:                X509_STORE_set_verify_cb(store, smime_cb);
1.11      inoguchi  907:                if (smime_config.vpm)
                    908:                        X509_STORE_set1_param(store, smime_config.vpm);
1.1       jsing     909:        }
                    910:        ret = 3;
                    911:
1.11      inoguchi  912:        if (smime_config.operation == SMIME_ENCRYPT) {
                    913:                if (smime_config.indef)
                    914:                        smime_config.flags |= PKCS7_STREAM;
                    915:                p7 = PKCS7_encrypt(encerts, in, smime_config.cipher, smime_config.flags);
                    916:        } else if (smime_config.operation & SMIME_SIGNERS) {
1.1       jsing     917:                int i;
                    918:                /*
                    919:                 * If detached data content we only enable streaming if
                    920:                 * S/MIME output format.
                    921:                 */
1.11      inoguchi  922:                if (smime_config.operation == SMIME_SIGN) {
                    923:                        if (smime_config.flags & PKCS7_DETACHED) {
                    924:                                if (smime_config.outformat == FORMAT_SMIME)
                    925:                                        smime_config.flags |= PKCS7_STREAM;
                    926:                        } else if (smime_config.indef)
                    927:                                smime_config.flags |= PKCS7_STREAM;
                    928:                        smime_config.flags |= PKCS7_PARTIAL;
                    929:                        p7 = PKCS7_sign(NULL, NULL, other, in, smime_config.flags);
1.1       jsing     930:                        if (!p7)
                    931:                                goto end;
                    932:                } else
1.11      inoguchi  933:                        smime_config.flags |= PKCS7_REUSE_DIGEST;
                    934:                for (i = 0; i < sk_OPENSSL_STRING_num(smime_config.sksigners); i++) {
                    935:                        smime_config.signerfile = sk_OPENSSL_STRING_value(smime_config.sksigners, i);
                    936:                        smime_config.keyfile = sk_OPENSSL_STRING_value(smime_config.skkeys, i);
                    937:                        signer = load_cert(bio_err, smime_config.signerfile, FORMAT_PEM, NULL,
1.4       bcook     938:                            "signer certificate");
1.1       jsing     939:                        if (!signer)
                    940:                                goto end;
1.11      inoguchi  941:                        key = load_key(bio_err, smime_config.keyfile, smime_config.keyform, 0, passin,
1.1       jsing     942:                            "signing key file");
                    943:                        if (!key)
                    944:                                goto end;
                    945:                        if (!PKCS7_sign_add_signer(p7, signer, key,
1.11      inoguchi  946:                                smime_config.sign_md, smime_config.flags))
1.1       jsing     947:                                goto end;
                    948:                        X509_free(signer);
                    949:                        signer = NULL;
                    950:                        EVP_PKEY_free(key);
                    951:                        key = NULL;
                    952:                }
                    953:                /* If not streaming or resigning finalize structure */
1.11      inoguchi  954:                if ((smime_config.operation == SMIME_SIGN) && !(smime_config.flags & PKCS7_STREAM)) {
                    955:                        if (!PKCS7_final(p7, in, smime_config.flags))
1.1       jsing     956:                                goto end;
                    957:                }
                    958:        }
                    959:        if (!p7) {
                    960:                BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
                    961:                goto end;
                    962:        }
                    963:        ret = 4;
1.11      inoguchi  964:        if (smime_config.operation == SMIME_DECRYPT) {
                    965:                if (!PKCS7_decrypt(p7, key, recip, out, smime_config.flags)) {
1.1       jsing     966:                        BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n");
                    967:                        goto end;
                    968:                }
1.11      inoguchi  969:        } else if (smime_config.operation == SMIME_VERIFY) {
1.12    ! inoguchi  970:                STACK_OF(X509) *signers;
1.11      inoguchi  971:                if (PKCS7_verify(p7, other, store, indata, out, smime_config.flags))
1.1       jsing     972:                        BIO_printf(bio_err, "Verification successful\n");
                    973:                else {
                    974:                        BIO_printf(bio_err, "Verification failure\n");
                    975:                        goto end;
                    976:                }
1.11      inoguchi  977:                signers = PKCS7_get0_signers(p7, other, smime_config.flags);
                    978:                if (!save_certs(smime_config.signerfile, signers)) {
1.1       jsing     979:                        BIO_printf(bio_err, "Error writing signers to %s\n",
1.11      inoguchi  980:                            smime_config.signerfile);
1.1       jsing     981:                        ret = 5;
                    982:                        goto end;
                    983:                }
                    984:                sk_X509_free(signers);
1.11      inoguchi  985:        } else if (smime_config.operation == SMIME_PK7OUT)
1.1       jsing     986:                PEM_write_bio_PKCS7(out, p7);
                    987:        else {
1.11      inoguchi  988:                if (smime_config.to)
                    989:                        BIO_printf(out, "To: %s\n", smime_config.to);
                    990:                if (smime_config.from)
                    991:                        BIO_printf(out, "From: %s\n", smime_config.from);
                    992:                if (smime_config.subject)
                    993:                        BIO_printf(out, "Subject: %s\n", smime_config.subject);
                    994:                if (smime_config.outformat == FORMAT_SMIME) {
                    995:                        if (smime_config.operation == SMIME_RESIGN)
                    996:                                SMIME_write_PKCS7(out, p7, indata, smime_config.flags);
1.1       jsing     997:                        else
1.11      inoguchi  998:                                SMIME_write_PKCS7(out, p7, in, smime_config.flags);
                    999:                } else if (smime_config.outformat == FORMAT_PEM)
                   1000:                        PEM_write_bio_PKCS7_stream(out, p7, in, smime_config.flags);
                   1001:                else if (smime_config.outformat == FORMAT_ASN1)
                   1002:                        i2d_PKCS7_bio_stream(out, p7, in, smime_config.flags);
1.1       jsing    1003:                else {
                   1004:                        BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
                   1005:                        goto end;
                   1006:                }
                   1007:        }
                   1008:        ret = 0;
1.10      jsing    1009:  end:
1.1       jsing    1010:        if (ret)
                   1011:                ERR_print_errors(bio_err);
                   1012:        sk_X509_pop_free(encerts, X509_free);
                   1013:        sk_X509_pop_free(other, X509_free);
1.11      inoguchi 1014:        X509_VERIFY_PARAM_free(smime_config.vpm);
                   1015:        sk_OPENSSL_STRING_free(smime_config.sksigners);
                   1016:        sk_OPENSSL_STRING_free(smime_config.skkeys);
1.1       jsing    1017:        X509_STORE_free(store);
                   1018:        X509_free(cert);
                   1019:        X509_free(recip);
                   1020:        X509_free(signer);
                   1021:        EVP_PKEY_free(key);
                   1022:        PKCS7_free(p7);
                   1023:        BIO_free(in);
                   1024:        BIO_free(indata);
                   1025:        BIO_free_all(out);
                   1026:        free(passin);
                   1027:
                   1028:        return (ret);
                   1029: }
                   1030:
                   1031: static int
1.12    ! inoguchi 1032: save_certs(char *signerfile, STACK_OF(X509) *signers)
1.1       jsing    1033: {
                   1034:        int i;
                   1035:        BIO *tmp;
1.12    ! inoguchi 1036:
1.1       jsing    1037:        if (!signerfile)
                   1038:                return 1;
                   1039:        tmp = BIO_new_file(signerfile, "w");
                   1040:        if (!tmp)
                   1041:                return 0;
                   1042:        for (i = 0; i < sk_X509_num(signers); i++)
                   1043:                PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
                   1044:        BIO_free(tmp);
1.12    ! inoguchi 1045:
1.1       jsing    1046:        return 1;
                   1047: }
                   1048:
                   1049: /* Minimal callback just to output policy info (if any) */
                   1050: static int
1.12    ! inoguchi 1051: smime_cb(int ok, X509_STORE_CTX *ctx)
1.1       jsing    1052: {
                   1053:        int error;
                   1054:
                   1055:        error = X509_STORE_CTX_get_error(ctx);
                   1056:
                   1057:        if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
                   1058:            && ((error != X509_V_OK) || (ok != 2)))
                   1059:                return ok;
                   1060:
                   1061:        policies_print(NULL, ctx);
                   1062:
                   1063:        return ok;
                   1064: }