Home | History | Annotate | Line # | Download | only in apps
      1  1.2  christos /*
      2  1.3  christos  * Copyright 1999-2025 The OpenSSL Project Authors. All Rights Reserved.
      3  1.1  christos  *
      4  1.2  christos  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  1.2  christos  * this file except in compliance with the License.  You can obtain a copy
      6  1.2  christos  * in the file LICENSE in the source distribution or at
      7  1.2  christos  * https://www.openssl.org/source/license.html
      8  1.1  christos  */
      9  1.1  christos 
     10  1.1  christos /* S/MIME utility function */
     11  1.1  christos 
     12  1.1  christos #include <stdio.h>
     13  1.1  christos #include <string.h>
     14  1.1  christos #include "apps.h"
     15  1.2  christos #include "progs.h"
     16  1.1  christos #include <openssl/crypto.h>
     17  1.1  christos #include <openssl/pem.h>
     18  1.1  christos #include <openssl/err.h>
     19  1.1  christos #include <openssl/x509_vfy.h>
     20  1.1  christos #include <openssl/x509v3.h>
     21  1.1  christos 
     22  1.1  christos static int save_certs(char *signerfile, STACK_OF(X509) *signers);
     23  1.1  christos static int smime_cb(int ok, X509_STORE_CTX *ctx);
     24  1.1  christos 
     25  1.2  christos #define SMIME_OP        0x10
     26  1.2  christos #define SMIME_IP        0x20
     27  1.2  christos #define SMIME_SIGNERS   0x40
     28  1.2  christos #define SMIME_ENCRYPT   (1 | SMIME_OP)
     29  1.2  christos #define SMIME_DECRYPT   (2 | SMIME_IP)
     30  1.2  christos #define SMIME_SIGN      (3 | SMIME_OP | SMIME_SIGNERS)
     31  1.2  christos #define SMIME_VERIFY    (4 | SMIME_IP)
     32  1.2  christos #define SMIME_PK7OUT    (5 | SMIME_IP | SMIME_OP)
     33  1.2  christos #define SMIME_RESIGN    (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
     34  1.2  christos 
     35  1.2  christos typedef enum OPTION_choice {
     36  1.2  christos     OPT_COMMON,
     37  1.2  christos     OPT_ENCRYPT, OPT_DECRYPT, OPT_SIGN, OPT_RESIGN, OPT_VERIFY,
     38  1.2  christos     OPT_PK7OUT, OPT_TEXT, OPT_NOINTERN, OPT_NOVERIFY, OPT_NOCHAIN,
     39  1.2  christos     OPT_NOCERTS, OPT_NOATTR, OPT_NODETACH, OPT_NOSMIMECAP,
     40  1.2  christos     OPT_BINARY, OPT_NOSIGS, OPT_STREAM, OPT_INDEF, OPT_NOINDEF,
     41  1.2  christos     OPT_CRLFEOL, OPT_ENGINE, OPT_PASSIN,
     42  1.2  christos     OPT_TO, OPT_FROM, OPT_SUBJECT, OPT_SIGNER, OPT_RECIP, OPT_MD,
     43  1.2  christos     OPT_CIPHER, OPT_INKEY, OPT_KEYFORM, OPT_CERTFILE, OPT_CAFILE,
     44  1.2  christos     OPT_CAPATH, OPT_CASTORE, OPT_NOCAFILE, OPT_NOCAPATH, OPT_NOCASTORE,
     45  1.2  christos     OPT_R_ENUM, OPT_PROV_ENUM, OPT_CONFIG,
     46  1.2  christos     OPT_V_ENUM,
     47  1.2  christos     OPT_IN, OPT_INFORM, OPT_OUT,
     48  1.2  christos     OPT_OUTFORM, OPT_CONTENT
     49  1.2  christos } OPTION_CHOICE;
     50  1.2  christos 
     51  1.2  christos const OPTIONS smime_options[] = {
     52  1.2  christos     {OPT_HELP_STR, 1, '-', "Usage: %s [options] [cert...]\n"},
     53  1.2  christos 
     54  1.2  christos     OPT_SECTION("General"),
     55  1.2  christos     {"help", OPT_HELP, '-', "Display this summary"},
     56  1.2  christos     {"in", OPT_IN, '<', "Input file"},
     57  1.2  christos     {"inform", OPT_INFORM, 'c', "Input format SMIME (default), PEM or DER"},
     58  1.2  christos     {"out", OPT_OUT, '>', "Output file"},
     59  1.2  christos     {"outform", OPT_OUTFORM, 'c',
     60  1.2  christos      "Output format SMIME (default), PEM or DER"},
     61  1.2  christos     {"inkey", OPT_INKEY, 's',
     62  1.2  christos      "Input private key (if not signer or recipient)"},
     63  1.2  christos     {"keyform", OPT_KEYFORM, 'f', "Input private key format (ENGINE, other values ignored)"},
     64  1.1  christos #ifndef OPENSSL_NO_ENGINE
     65  1.2  christos     {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
     66  1.1  christos #endif
     67  1.2  christos     {"stream", OPT_STREAM, '-', "Enable CMS streaming" },
     68  1.2  christos     {"indef", OPT_INDEF, '-', "Same as -stream" },
     69  1.2  christos     {"noindef", OPT_NOINDEF, '-', "Disable CMS streaming"},
     70  1.2  christos     OPT_CONFIG_OPTION,
     71  1.2  christos 
     72  1.2  christos     OPT_SECTION("Action"),
     73  1.2  christos     {"encrypt", OPT_ENCRYPT, '-', "Encrypt message"},
     74  1.2  christos     {"decrypt", OPT_DECRYPT, '-', "Decrypt encrypted message"},
     75  1.2  christos     {"sign", OPT_SIGN, '-', "Sign message"},
     76  1.2  christos     {"resign", OPT_RESIGN, '-', "Resign a signed message"},
     77  1.2  christos     {"verify", OPT_VERIFY, '-', "Verify signed message"},
     78  1.2  christos 
     79  1.2  christos     OPT_SECTION("Signing/Encryption"),
     80  1.2  christos     {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
     81  1.2  christos     {"md", OPT_MD, 's', "Digest algorithm to use when signing or resigning"},
     82  1.2  christos     {"", OPT_CIPHER, '-', "Any supported cipher"},
     83  1.2  christos     {"pk7out", OPT_PK7OUT, '-', "Output PKCS#7 structure"},
     84  1.2  christos     {"nointern", OPT_NOINTERN, '-',
     85  1.2  christos      "Don't search certificates in message for signer"},
     86  1.2  christos     {"nodetach", OPT_NODETACH, '-', "Use opaque signing"},
     87  1.2  christos     {"noattr", OPT_NOATTR, '-', "Don't include any signed attributes"},
     88  1.2  christos     {"binary", OPT_BINARY, '-', "Don't translate message to text"},
     89  1.2  christos     {"signer", OPT_SIGNER, 's', "Signer certificate file"},
     90  1.2  christos     {"content", OPT_CONTENT, '<',
     91  1.2  christos      "Supply or override content for detached signature"},
     92  1.2  christos     {"nocerts", OPT_NOCERTS, '-',
     93  1.2  christos      "Don't include signers certificate when signing"},
     94  1.2  christos 
     95  1.2  christos     OPT_SECTION("Verification/Decryption"),
     96  1.2  christos     {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"},
     97  1.2  christos     {"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"},
     98  1.2  christos 
     99  1.2  christos     {"certfile", OPT_CERTFILE, '<', "Other certificates file"},
    100  1.2  christos     {"recip", OPT_RECIP, '<', "Recipient certificate file for decryption"},
    101  1.2  christos 
    102  1.2  christos     OPT_SECTION("Email"),
    103  1.2  christos     {"to", OPT_TO, 's', "To address"},
    104  1.2  christos     {"from", OPT_FROM, 's', "From address"},
    105  1.2  christos     {"subject", OPT_SUBJECT, 's', "Subject"},
    106  1.2  christos     {"text", OPT_TEXT, '-', "Include or delete text MIME headers"},
    107  1.2  christos     {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"},
    108  1.2  christos 
    109  1.2  christos     OPT_SECTION("Certificate chain"),
    110  1.2  christos     {"CApath", OPT_CAPATH, '/', "Trusted certificates directory"},
    111  1.2  christos     {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"},
    112  1.2  christos     {"CAstore", OPT_CASTORE, ':', "Trusted certificates store URI"},
    113  1.2  christos     {"no-CAfile", OPT_NOCAFILE, '-',
    114  1.2  christos      "Do not load the default certificates file"},
    115  1.2  christos     {"no-CApath", OPT_NOCAPATH, '-',
    116  1.2  christos      "Do not load certificates from the default certificates directory"},
    117  1.2  christos     {"no-CAstore", OPT_NOCASTORE, '-',
    118  1.2  christos      "Do not load certificates from the default certificates store"},
    119  1.2  christos     {"nochain", OPT_NOCHAIN, '-',
    120  1.2  christos      "set PKCS7_NOCHAIN so certificates contained in the message are not used as untrusted CAs" },
    121  1.2  christos     {"crlfeol", OPT_CRLFEOL, '-', "Use CRLF as EOL termination instead of LF only"},
    122  1.2  christos 
    123  1.2  christos     OPT_R_OPTIONS,
    124  1.2  christos     OPT_V_OPTIONS,
    125  1.2  christos     OPT_PROV_OPTIONS,
    126  1.2  christos 
    127  1.2  christos     OPT_PARAMETERS(),
    128  1.2  christos     {"cert", 0, 0, "Recipient certs, used when encrypting"},
    129  1.2  christos     {NULL}
    130  1.2  christos };
    131  1.2  christos 
    132  1.2  christos int smime_main(int argc, char **argv)
    133  1.2  christos {
    134  1.2  christos     CONF *conf = NULL;
    135  1.2  christos     BIO *in = NULL, *out = NULL, *indata = NULL;
    136  1.2  christos     EVP_PKEY *key = NULL;
    137  1.2  christos     PKCS7 *p7 = NULL;
    138  1.2  christos     STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL;
    139  1.2  christos     STACK_OF(X509) *encerts = NULL, *other = NULL;
    140  1.2  christos     X509 *cert = NULL, *recip = NULL, *signer = NULL;
    141  1.2  christos     X509_STORE *store = NULL;
    142  1.2  christos     X509_VERIFY_PARAM *vpm = NULL;
    143  1.2  christos     EVP_CIPHER *cipher = NULL;
    144  1.2  christos     EVP_MD *sign_md = NULL;
    145  1.2  christos     const char *CAfile = NULL, *CApath = NULL, *CAstore = NULL, *prog = NULL;
    146  1.2  christos     char *certfile = NULL, *keyfile = NULL, *contfile = NULL;
    147  1.2  christos     char *infile = NULL, *outfile = NULL, *signerfile = NULL, *recipfile = NULL;
    148  1.2  christos     char *passinarg = NULL, *passin = NULL, *to = NULL, *from = NULL;
    149  1.2  christos     char *subject = NULL, *digestname = NULL, *ciphername = NULL;
    150  1.2  christos     OPTION_CHOICE o;
    151  1.2  christos     int noCApath = 0, noCAfile = 0, noCAstore = 0;
    152  1.2  christos     int flags = PKCS7_DETACHED, operation = 0, ret = 0, indef = 0;
    153  1.2  christos     int informat = FORMAT_SMIME, outformat = FORMAT_SMIME, keyform =
    154  1.2  christos         FORMAT_UNDEF;
    155  1.2  christos     int vpmtouched = 0, rv = 0;
    156  1.2  christos     ENGINE *e = NULL;
    157  1.2  christos     const char *mime_eol = "\n";
    158  1.2  christos     OSSL_LIB_CTX *libctx = app_get0_libctx();
    159  1.2  christos 
    160  1.2  christos     if ((vpm = X509_VERIFY_PARAM_new()) == NULL)
    161  1.2  christos         return 1;
    162  1.2  christos 
    163  1.2  christos     prog = opt_init(argc, argv, smime_options);
    164  1.2  christos     while ((o = opt_next()) != OPT_EOF) {
    165  1.2  christos         switch (o) {
    166  1.2  christos         case OPT_EOF:
    167  1.2  christos         case OPT_ERR:
    168  1.2  christos  opthelp:
    169  1.2  christos             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
    170  1.2  christos             goto end;
    171  1.2  christos         case OPT_HELP:
    172  1.2  christos             opt_help(smime_options);
    173  1.2  christos             ret = 0;
    174  1.2  christos             goto end;
    175  1.2  christos         case OPT_INFORM:
    176  1.2  christos             if (!opt_format(opt_arg(), OPT_FMT_PDS, &informat))
    177  1.2  christos                 goto opthelp;
    178  1.2  christos             break;
    179  1.2  christos         case OPT_IN:
    180  1.2  christos             infile = opt_arg();
    181  1.2  christos             break;
    182  1.2  christos         case OPT_OUTFORM:
    183  1.2  christos             if (!opt_format(opt_arg(), OPT_FMT_PDS, &outformat))
    184  1.2  christos                 goto opthelp;
    185  1.2  christos             break;
    186  1.2  christos         case OPT_OUT:
    187  1.2  christos             outfile = opt_arg();
    188  1.2  christos             break;
    189  1.2  christos         case OPT_ENCRYPT:
    190  1.2  christos             operation = SMIME_ENCRYPT;
    191  1.2  christos             break;
    192  1.2  christos         case OPT_DECRYPT:
    193  1.2  christos             operation = SMIME_DECRYPT;
    194  1.2  christos             break;
    195  1.2  christos         case OPT_SIGN:
    196  1.2  christos             operation = SMIME_SIGN;
    197  1.2  christos             break;
    198  1.2  christos         case OPT_RESIGN:
    199  1.2  christos             operation = SMIME_RESIGN;
    200  1.2  christos             break;
    201  1.2  christos         case OPT_VERIFY:
    202  1.2  christos             operation = SMIME_VERIFY;
    203  1.2  christos             break;
    204  1.2  christos         case OPT_PK7OUT:
    205  1.2  christos             operation = SMIME_PK7OUT;
    206  1.2  christos             break;
    207  1.2  christos         case OPT_TEXT:
    208  1.2  christos             flags |= PKCS7_TEXT;
    209  1.2  christos             break;
    210  1.2  christos         case OPT_NOINTERN:
    211  1.2  christos             flags |= PKCS7_NOINTERN;
    212  1.2  christos             break;
    213  1.2  christos         case OPT_NOVERIFY:
    214  1.2  christos             flags |= PKCS7_NOVERIFY;
    215  1.2  christos             break;
    216  1.2  christos         case OPT_NOCHAIN:
    217  1.2  christos             flags |= PKCS7_NOCHAIN;
    218  1.2  christos             break;
    219  1.2  christos         case OPT_NOCERTS:
    220  1.2  christos             flags |= PKCS7_NOCERTS;
    221  1.2  christos             break;
    222  1.2  christos         case OPT_NOATTR:
    223  1.2  christos             flags |= PKCS7_NOATTR;
    224  1.2  christos             break;
    225  1.2  christos         case OPT_NODETACH:
    226  1.2  christos             flags &= ~PKCS7_DETACHED;
    227  1.2  christos             break;
    228  1.2  christos         case OPT_NOSMIMECAP:
    229  1.2  christos             flags |= PKCS7_NOSMIMECAP;
    230  1.2  christos             break;
    231  1.2  christos         case OPT_BINARY:
    232  1.2  christos             flags |= PKCS7_BINARY;
    233  1.2  christos             break;
    234  1.2  christos         case OPT_NOSIGS:
    235  1.2  christos             flags |= PKCS7_NOSIGS;
    236  1.2  christos             break;
    237  1.2  christos         case OPT_STREAM:
    238  1.2  christos         case OPT_INDEF:
    239  1.2  christos             indef = 1;
    240  1.2  christos             break;
    241  1.2  christos         case OPT_NOINDEF:
    242  1.2  christos             indef = 0;
    243  1.2  christos             break;
    244  1.2  christos         case OPT_CRLFEOL:
    245  1.2  christos             flags |= PKCS7_CRLFEOL;
    246  1.2  christos             mime_eol = "\r\n";
    247  1.2  christos             break;
    248  1.2  christos         case OPT_R_CASES:
    249  1.2  christos             if (!opt_rand(o))
    250  1.2  christos                 goto end;
    251  1.2  christos             break;
    252  1.2  christos         case OPT_PROV_CASES:
    253  1.2  christos             if (!opt_provider(o))
    254  1.2  christos                 goto end;
    255  1.2  christos             break;
    256  1.2  christos         case OPT_CONFIG:
    257  1.2  christos             conf = app_load_config_modules(opt_arg());
    258  1.2  christos             if (conf == NULL)
    259  1.2  christos                 goto end;
    260  1.2  christos             break;
    261  1.2  christos         case OPT_ENGINE:
    262  1.2  christos             e = setup_engine(opt_arg(), 0);
    263  1.2  christos             break;
    264  1.2  christos         case OPT_PASSIN:
    265  1.2  christos             passinarg = opt_arg();
    266  1.2  christos             break;
    267  1.2  christos         case OPT_TO:
    268  1.2  christos             to = opt_arg();
    269  1.2  christos             break;
    270  1.2  christos         case OPT_FROM:
    271  1.2  christos             from = opt_arg();
    272  1.2  christos             break;
    273  1.2  christos         case OPT_SUBJECT:
    274  1.2  christos             subject = opt_arg();
    275  1.2  christos             break;
    276  1.2  christos         case OPT_SIGNER:
    277  1.2  christos             /* If previous -signer argument add signer to list */
    278  1.2  christos             if (signerfile != NULL) {
    279  1.2  christos                 if (sksigners == NULL
    280  1.2  christos                     && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
    281  1.2  christos                     goto end;
    282  1.3  christos                 if (sk_OPENSSL_STRING_push(sksigners, signerfile) <= 0)
    283  1.3  christos                     goto end;
    284  1.2  christos                 if (keyfile == NULL)
    285  1.2  christos                     keyfile = signerfile;
    286  1.2  christos                 if (skkeys == NULL
    287  1.2  christos                     && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
    288  1.2  christos                     goto end;
    289  1.3  christos                 if (sk_OPENSSL_STRING_push(skkeys, keyfile) <= 0)
    290  1.3  christos                     goto end;
    291  1.2  christos                 keyfile = NULL;
    292  1.2  christos             }
    293  1.2  christos             signerfile = opt_arg();
    294  1.2  christos             break;
    295  1.2  christos         case OPT_RECIP:
    296  1.2  christos             recipfile = opt_arg();
    297  1.2  christos             break;
    298  1.2  christos         case OPT_MD:
    299  1.2  christos             digestname = opt_arg();
    300  1.2  christos             break;
    301  1.2  christos         case OPT_CIPHER:
    302  1.2  christos             ciphername = opt_unknown();
    303  1.2  christos             break;
    304  1.2  christos         case OPT_INKEY:
    305  1.2  christos             /* If previous -inkey argument add signer to list */
    306  1.2  christos             if (keyfile != NULL) {
    307  1.2  christos                 if (signerfile == NULL) {
    308  1.2  christos                     BIO_printf(bio_err,
    309  1.2  christos                                "%s: Must have -signer before -inkey\n", prog);
    310  1.2  christos                     goto opthelp;
    311  1.2  christos                 }
    312  1.2  christos                 if (sksigners == NULL
    313  1.2  christos                     && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
    314  1.2  christos                     goto end;
    315  1.3  christos                 if (sk_OPENSSL_STRING_push(sksigners, signerfile) <= 0)
    316  1.3  christos                     goto end;
    317  1.2  christos                 signerfile = NULL;
    318  1.2  christos                 if (skkeys == NULL
    319  1.2  christos                     && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
    320  1.2  christos                     goto end;
    321  1.3  christos                 if (sk_OPENSSL_STRING_push(skkeys, keyfile) <= 0)
    322  1.3  christos                     goto end;
    323  1.2  christos             }
    324  1.2  christos             keyfile = opt_arg();
    325  1.2  christos             break;
    326  1.2  christos         case OPT_KEYFORM:
    327  1.2  christos             if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform))
    328  1.2  christos                 goto opthelp;
    329  1.2  christos             break;
    330  1.2  christos         case OPT_CERTFILE:
    331  1.2  christos             certfile = opt_arg();
    332  1.2  christos             break;
    333  1.2  christos         case OPT_CAFILE:
    334  1.2  christos             CAfile = opt_arg();
    335  1.2  christos             break;
    336  1.2  christos         case OPT_CAPATH:
    337  1.2  christos             CApath = opt_arg();
    338  1.2  christos             break;
    339  1.2  christos         case OPT_CASTORE:
    340  1.2  christos             CAstore = opt_arg();
    341  1.2  christos             break;
    342  1.2  christos         case OPT_NOCAFILE:
    343  1.2  christos             noCAfile = 1;
    344  1.2  christos             break;
    345  1.2  christos         case OPT_NOCAPATH:
    346  1.2  christos             noCApath = 1;
    347  1.2  christos             break;
    348  1.2  christos         case OPT_NOCASTORE:
    349  1.2  christos             noCAstore = 1;
    350  1.2  christos             break;
    351  1.2  christos         case OPT_CONTENT:
    352  1.2  christos             contfile = opt_arg();
    353  1.2  christos             break;
    354  1.2  christos         case OPT_V_CASES:
    355  1.2  christos             if (!opt_verify(o, vpm))
    356  1.2  christos                 goto opthelp;
    357  1.2  christos             vpmtouched++;
    358  1.2  christos             break;
    359  1.2  christos         }
    360  1.2  christos     }
    361  1.2  christos 
    362  1.2  christos     /* Extra arguments are files with recipient keys. */
    363  1.2  christos     argc = opt_num_rest();
    364  1.2  christos     argv = opt_rest();
    365  1.2  christos 
    366  1.2  christos     if (!app_RAND_load())
    367  1.2  christos         goto end;
    368  1.2  christos 
    369  1.2  christos     if (digestname != NULL) {
    370  1.2  christos         if (!opt_md(digestname, &sign_md))
    371  1.2  christos             goto opthelp;
    372  1.2  christos     }
    373  1.2  christos     if (ciphername != NULL) {
    374  1.2  christos         if (!opt_cipher_any(ciphername, &cipher))
    375  1.2  christos             goto opthelp;
    376  1.2  christos     }
    377  1.2  christos     if (!(operation & SMIME_SIGNERS) && (skkeys != NULL || sksigners != NULL)) {
    378  1.2  christos         BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
    379  1.2  christos         goto opthelp;
    380  1.2  christos     }
    381  1.2  christos     if (!operation) {
    382  1.2  christos         BIO_puts(bio_err,
    383  1.2  christos                 "No operation (-encrypt|-sign|...) specified\n");
    384  1.2  christos         goto opthelp;
    385  1.2  christos     }
    386  1.2  christos 
    387  1.2  christos     if (operation & SMIME_SIGNERS) {
    388  1.2  christos         /* Check to see if any final signer needs to be appended */
    389  1.2  christos         if (keyfile && !signerfile) {
    390  1.2  christos             BIO_puts(bio_err, "Illegal -inkey without -signer\n");
    391  1.2  christos             goto opthelp;
    392  1.2  christos         }
    393  1.2  christos         if (signerfile != NULL) {
    394  1.2  christos             if (sksigners == NULL
    395  1.2  christos                 && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
    396  1.2  christos                 goto end;
    397  1.3  christos             if (sk_OPENSSL_STRING_push(sksigners, signerfile) <= 0)
    398  1.3  christos                 goto end;
    399  1.2  christos             if (!skkeys && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
    400  1.2  christos                 goto end;
    401  1.2  christos             if (!keyfile)
    402  1.2  christos                 keyfile = signerfile;
    403  1.3  christos             if (sk_OPENSSL_STRING_push(skkeys, keyfile) <= 0)
    404  1.3  christos                 goto end;
    405  1.2  christos         }
    406  1.2  christos         if (sksigners == NULL) {
    407  1.2  christos             BIO_printf(bio_err, "No signer certificate specified\n");
    408  1.2  christos             goto opthelp;
    409  1.2  christos         }
    410  1.2  christos         signerfile = NULL;
    411  1.2  christos         keyfile = NULL;
    412  1.2  christos     } else if (operation == SMIME_DECRYPT) {
    413  1.2  christos         if (recipfile == NULL && keyfile == NULL) {
    414  1.2  christos             BIO_printf(bio_err,
    415  1.2  christos                        "No recipient certificate or key specified\n");
    416  1.2  christos             goto opthelp;
    417  1.2  christos         }
    418  1.2  christos     } else if (operation == SMIME_ENCRYPT) {
    419  1.2  christos         if (argc == 0) {
    420  1.2  christos             BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
    421  1.2  christos             goto opthelp;
    422  1.2  christos         }
    423  1.2  christos     }
    424  1.2  christos 
    425  1.2  christos     if (!app_passwd(passinarg, NULL, &passin, NULL)) {
    426  1.2  christos         BIO_printf(bio_err, "Error getting password\n");
    427  1.2  christos         goto end;
    428  1.2  christos     }
    429  1.2  christos 
    430  1.2  christos     ret = 2;
    431  1.2  christos 
    432  1.2  christos     if (!(operation & SMIME_SIGNERS))
    433  1.2  christos         flags &= ~PKCS7_DETACHED;
    434  1.2  christos 
    435  1.2  christos     if (!(operation & SMIME_OP)) {
    436  1.2  christos         if (flags & PKCS7_BINARY)
    437  1.2  christos             outformat = FORMAT_BINARY;
    438  1.2  christos     }
    439  1.2  christos 
    440  1.2  christos     if (!(operation & SMIME_IP)) {
    441  1.2  christos         if (flags & PKCS7_BINARY)
    442  1.2  christos             informat = FORMAT_BINARY;
    443  1.2  christos     }
    444  1.1  christos 
    445  1.2  christos     if (operation == SMIME_ENCRYPT) {
    446  1.2  christos         if (cipher == NULL) {
    447  1.1  christos #ifndef OPENSSL_NO_DES
    448  1.2  christos             cipher = (EVP_CIPHER *)EVP_des_ede3_cbc();
    449  1.1  christos #else
    450  1.2  christos             BIO_printf(bio_err, "No cipher selected\n");
    451  1.2  christos             goto end;
    452  1.1  christos #endif
    453  1.2  christos         }
    454  1.2  christos         encerts = sk_X509_new_null();
    455  1.2  christos         if (encerts == NULL)
    456  1.2  christos             goto end;
    457  1.2  christos         while (*argv != NULL) {
    458  1.2  christos             cert = load_cert(*argv, FORMAT_UNDEF,
    459  1.2  christos                              "recipient certificate file");
    460  1.2  christos             if (cert == NULL)
    461  1.2  christos                 goto end;
    462  1.2  christos             if (!sk_X509_push(encerts, cert))
    463  1.2  christos                 goto end;
    464  1.2  christos             cert = NULL;
    465  1.2  christos             argv++;
    466  1.2  christos         }
    467  1.2  christos     }
    468  1.2  christos 
    469  1.2  christos     if (certfile != NULL) {
    470  1.2  christos         if (!load_certs(certfile, 0, &other, NULL, "certificates")) {
    471  1.2  christos             ERR_print_errors(bio_err);
    472  1.2  christos             goto end;
    473  1.2  christos         }
    474  1.2  christos     }
    475  1.2  christos 
    476  1.2  christos     if (recipfile != NULL && (operation == SMIME_DECRYPT)) {
    477  1.2  christos         if ((recip = load_cert(recipfile, FORMAT_UNDEF,
    478  1.2  christos                                "recipient certificate file")) == NULL) {
    479  1.2  christos             ERR_print_errors(bio_err);
    480  1.2  christos             goto end;
    481  1.2  christos         }
    482  1.2  christos     }
    483  1.2  christos 
    484  1.2  christos     if (operation == SMIME_DECRYPT) {
    485  1.2  christos         if (keyfile == NULL)
    486  1.2  christos             keyfile = recipfile;
    487  1.2  christos     } else if (operation == SMIME_SIGN) {
    488  1.2  christos         if (keyfile == NULL)
    489  1.2  christos             keyfile = signerfile;
    490  1.2  christos     } else {
    491  1.2  christos         keyfile = NULL;
    492  1.2  christos     }
    493  1.2  christos 
    494  1.2  christos     if (keyfile != NULL) {
    495  1.2  christos         key = load_key(keyfile, keyform, 0, passin, e, "signing key");
    496  1.2  christos         if (key == NULL)
    497  1.2  christos             goto end;
    498  1.2  christos     }
    499  1.2  christos 
    500  1.2  christos     in = bio_open_default(infile, 'r', informat);
    501  1.2  christos     if (in == NULL)
    502  1.2  christos         goto end;
    503  1.2  christos 
    504  1.2  christos     if (operation & SMIME_IP) {
    505  1.2  christos         PKCS7 *p7_in = NULL;
    506  1.2  christos 
    507  1.2  christos         p7 = PKCS7_new_ex(libctx, app_get0_propq());
    508  1.2  christos         if (p7 == NULL) {
    509  1.2  christos             BIO_printf(bio_err, "Error allocating PKCS7 object\n");
    510  1.2  christos             goto end;
    511  1.2  christos         }
    512  1.2  christos         if (informat == FORMAT_SMIME) {
    513  1.2  christos             p7_in = SMIME_read_PKCS7_ex(in, &indata, &p7);
    514  1.2  christos         } else if (informat == FORMAT_PEM) {
    515  1.2  christos             p7_in = PEM_read_bio_PKCS7(in, &p7, NULL, NULL);
    516  1.2  christos         } else if (informat == FORMAT_ASN1) {
    517  1.2  christos             p7_in = d2i_PKCS7_bio(in, &p7);
    518  1.2  christos         } else {
    519  1.2  christos             BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
    520  1.2  christos             goto end;
    521  1.2  christos         }
    522  1.2  christos 
    523  1.2  christos         if (p7_in == NULL) {
    524  1.2  christos             BIO_printf(bio_err, "Error reading S/MIME message\n");
    525  1.2  christos             goto end;
    526  1.2  christos         }
    527  1.2  christos         if (contfile != NULL) {
    528  1.2  christos             BIO_free(indata);
    529  1.2  christos             if ((indata = BIO_new_file(contfile, "rb")) == NULL) {
    530  1.2  christos                 BIO_printf(bio_err, "Can't read content file %s\n", contfile);
    531  1.2  christos                 goto end;
    532  1.2  christos             }
    533  1.2  christos         }
    534  1.2  christos     }
    535  1.2  christos 
    536  1.2  christos     out = bio_open_default(outfile, 'w', outformat);
    537  1.2  christos     if (out == NULL)
    538  1.2  christos         goto end;
    539  1.2  christos 
    540  1.2  christos     if (operation == SMIME_VERIFY) {
    541  1.2  christos         if ((store = setup_verify(CAfile, noCAfile, CApath, noCApath,
    542  1.2  christos                                   CAstore, noCAstore)) == NULL)
    543  1.2  christos             goto end;
    544  1.2  christos         X509_STORE_set_verify_cb(store, smime_cb);
    545  1.2  christos         if (vpmtouched)
    546  1.2  christos             X509_STORE_set1_param(store, vpm);
    547  1.2  christos     }
    548  1.2  christos 
    549  1.2  christos     ret = 3;
    550  1.2  christos 
    551  1.2  christos     if (operation == SMIME_ENCRYPT) {
    552  1.2  christos         if (indef)
    553  1.2  christos             flags |= PKCS7_STREAM;
    554  1.2  christos         p7 = PKCS7_encrypt_ex(encerts, in, cipher, flags, libctx, app_get0_propq());
    555  1.2  christos     } else if (operation & SMIME_SIGNERS) {
    556  1.2  christos         int i;
    557  1.2  christos         /*
    558  1.2  christos          * If detached data content we only enable streaming if S/MIME output
    559  1.2  christos          * format.
    560  1.2  christos          */
    561  1.2  christos         if (operation == SMIME_SIGN) {
    562  1.2  christos             if (flags & PKCS7_DETACHED) {
    563  1.2  christos                 if (outformat == FORMAT_SMIME)
    564  1.2  christos                     flags |= PKCS7_STREAM;
    565  1.2  christos             } else if (indef) {
    566  1.2  christos                 flags |= PKCS7_STREAM;
    567  1.2  christos             }
    568  1.2  christos             flags |= PKCS7_PARTIAL;
    569  1.2  christos             p7 = PKCS7_sign_ex(NULL, NULL, other, in, flags, libctx, app_get0_propq());
    570  1.2  christos             if (p7 == NULL)
    571  1.2  christos                 goto end;
    572  1.2  christos             if (flags & PKCS7_NOCERTS) {
    573  1.2  christos                 for (i = 0; i < sk_X509_num(other); i++) {
    574  1.2  christos                     X509 *x = sk_X509_value(other, i);
    575  1.2  christos                     PKCS7_add_certificate(p7, x);
    576  1.2  christos                 }
    577  1.2  christos             }
    578  1.2  christos         } else {
    579  1.2  christos             flags |= PKCS7_REUSE_DIGEST;
    580  1.2  christos         }
    581  1.2  christos         for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) {
    582  1.2  christos             signerfile = sk_OPENSSL_STRING_value(sksigners, i);
    583  1.2  christos             keyfile = sk_OPENSSL_STRING_value(skkeys, i);
    584  1.2  christos             signer = load_cert(signerfile, FORMAT_UNDEF, "signer certificate");
    585  1.2  christos             if (signer == NULL)
    586  1.2  christos                 goto end;
    587  1.2  christos             key = load_key(keyfile, keyform, 0, passin, e, "signing key");
    588  1.2  christos             if (key == NULL)
    589  1.2  christos                 goto end;
    590  1.2  christos 
    591  1.2  christos             if (!PKCS7_sign_add_signer(p7, signer, key, sign_md, flags))
    592  1.2  christos                 goto end;
    593  1.2  christos             X509_free(signer);
    594  1.2  christos             signer = NULL;
    595  1.2  christos             EVP_PKEY_free(key);
    596  1.2  christos             key = NULL;
    597  1.2  christos         }
    598  1.2  christos         /* If not streaming or resigning finalize structure */
    599  1.2  christos         if ((operation == SMIME_SIGN) && !(flags & PKCS7_STREAM)) {
    600  1.2  christos             if (!PKCS7_final(p7, in, flags))
    601  1.2  christos                 goto end;
    602  1.2  christos         }
    603  1.2  christos     }
    604  1.2  christos 
    605  1.2  christos     if (p7 == NULL) {
    606  1.2  christos         BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
    607  1.2  christos         goto end;
    608  1.2  christos     }
    609  1.2  christos 
    610  1.2  christos     ret = 4;
    611  1.2  christos     if (operation == SMIME_DECRYPT) {
    612  1.2  christos         if (!PKCS7_decrypt(p7, key, recip, out, flags)) {
    613  1.2  christos             BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n");
    614  1.2  christos             goto end;
    615  1.2  christos         }
    616  1.2  christos     } else if (operation == SMIME_VERIFY) {
    617  1.2  christos         STACK_OF(X509) *signers;
    618  1.2  christos         if (PKCS7_verify(p7, other, store, indata, out, flags))
    619  1.2  christos             BIO_printf(bio_err, "Verification successful\n");
    620  1.2  christos         else {
    621  1.2  christos             BIO_printf(bio_err, "Verification failure\n");
    622  1.2  christos             goto end;
    623  1.2  christos         }
    624  1.2  christos         signers = PKCS7_get0_signers(p7, other, flags);
    625  1.2  christos         if (!save_certs(signerfile, signers)) {
    626  1.2  christos             BIO_printf(bio_err, "Error writing signers to %s\n", signerfile);
    627  1.2  christos             ret = 5;
    628  1.2  christos             goto end;
    629  1.2  christos         }
    630  1.2  christos         sk_X509_free(signers);
    631  1.2  christos     } else if (operation == SMIME_PK7OUT) {
    632  1.2  christos         PEM_write_bio_PKCS7(out, p7);
    633  1.2  christos     } else {
    634  1.2  christos         if (to)
    635  1.2  christos             BIO_printf(out, "To: %s%s", to, mime_eol);
    636  1.2  christos         if (from)
    637  1.2  christos             BIO_printf(out, "From: %s%s", from, mime_eol);
    638  1.2  christos         if (subject)
    639  1.2  christos             BIO_printf(out, "Subject: %s%s", subject, mime_eol);
    640  1.2  christos         if (outformat == FORMAT_SMIME) {
    641  1.2  christos             if (operation == SMIME_RESIGN)
    642  1.2  christos                 rv = SMIME_write_PKCS7(out, p7, indata, flags);
    643  1.2  christos             else
    644  1.2  christos                 rv = SMIME_write_PKCS7(out, p7, in, flags);
    645  1.2  christos         } else if (outformat == FORMAT_PEM) {
    646  1.2  christos             rv = PEM_write_bio_PKCS7_stream(out, p7, in, flags);
    647  1.2  christos         } else if (outformat == FORMAT_ASN1) {
    648  1.2  christos             rv = i2d_PKCS7_bio_stream(out, p7, in, flags);
    649  1.2  christos         } else {
    650  1.2  christos             BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
    651  1.2  christos             goto end;
    652  1.2  christos         }
    653  1.2  christos         if (rv == 0) {
    654  1.2  christos             BIO_printf(bio_err, "Error writing output\n");
    655  1.2  christos             ret = 3;
    656  1.2  christos             goto end;
    657  1.2  christos         }
    658  1.2  christos     }
    659  1.2  christos     ret = 0;
    660  1.2  christos  end:
    661  1.2  christos     if (ret)
    662  1.2  christos         ERR_print_errors(bio_err);
    663  1.2  christos     sk_X509_pop_free(encerts, X509_free);
    664  1.2  christos     sk_X509_pop_free(other, X509_free);
    665  1.2  christos     X509_VERIFY_PARAM_free(vpm);
    666  1.2  christos     sk_OPENSSL_STRING_free(sksigners);
    667  1.2  christos     sk_OPENSSL_STRING_free(skkeys);
    668  1.2  christos     X509_STORE_free(store);
    669  1.2  christos     X509_free(cert);
    670  1.2  christos     X509_free(recip);
    671  1.2  christos     X509_free(signer);
    672  1.2  christos     EVP_PKEY_free(key);
    673  1.2  christos     EVP_MD_free(sign_md);
    674  1.2  christos     EVP_CIPHER_free(cipher);
    675  1.2  christos     PKCS7_free(p7);
    676  1.2  christos     release_engine(e);
    677  1.2  christos     BIO_free(in);
    678  1.2  christos     BIO_free(indata);
    679  1.2  christos     BIO_free_all(out);
    680  1.2  christos     OPENSSL_free(passin);
    681  1.2  christos     NCONF_free(conf);
    682  1.2  christos     return ret;
    683  1.1  christos }
    684  1.1  christos 
    685  1.1  christos static int save_certs(char *signerfile, STACK_OF(X509) *signers)
    686  1.2  christos {
    687  1.2  christos     int i;
    688  1.2  christos     BIO *tmp;
    689  1.2  christos 
    690  1.2  christos     if (signerfile == NULL)
    691  1.2  christos         return 1;
    692  1.2  christos     tmp = BIO_new_file(signerfile, "w");
    693  1.2  christos     if (tmp == NULL)
    694  1.2  christos         return 0;
    695  1.2  christos     for (i = 0; i < sk_X509_num(signers); i++)
    696  1.2  christos         PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
    697  1.2  christos     BIO_free(tmp);
    698  1.2  christos     return 1;
    699  1.2  christos }
    700  1.1  christos 
    701  1.1  christos /* Minimal callback just to output policy info (if any) */
    702  1.1  christos 
    703  1.1  christos static int smime_cb(int ok, X509_STORE_CTX *ctx)
    704  1.2  christos {
    705  1.2  christos     int error;
    706  1.1  christos 
    707  1.2  christos     error = X509_STORE_CTX_get_error(ctx);
    708  1.1  christos 
    709  1.2  christos     if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
    710  1.2  christos         && ((error != X509_V_OK) || (ok != 2)))
    711  1.2  christos         return ok;
    712  1.1  christos 
    713  1.2  christos     policies_print(ctx);
    714  1.1  christos 
    715  1.2  christos     return ok;
    716  1.2  christos }
    717