+ {"stream", OPT_STREAM, '-', "Enable CMS streaming" },
+ {"indef", OPT_INDEF, '-', "Same as -stream" },
+ {"noindef", OPT_NOINDEF, '-', "Disable CMS streaming"},
+
+ OPT_SECTION("Action"),
+ {"encrypt", OPT_ENCRYPT, '-', "Encrypt message"},
+ {"decrypt", OPT_DECRYPT, '-', "Decrypt encrypted message"},
+ {"sign", OPT_SIGN, '-', "Sign message"},
+ {"resign", OPT_RESIGN, '-', "Resign a signed message"},
+ {"verify", OPT_VERIFY, '-', "Verify signed message"},
+
+ OPT_SECTION("Signing/Encryption"),
+ {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
+ {"md", OPT_MD, 's', "Digest algorithm to use when signing or resigning"},
+ {"", OPT_CIPHER, '-', "Any supported cipher"},
+ {"pk7out", OPT_PK7OUT, '-', "Output PKCS#7 structure"},
+ {"nointern", OPT_NOINTERN, '-',
+ "Don't search certificates in message for signer"},
+ {"nodetach", OPT_NODETACH, '-', "Use opaque signing"},
+ {"noattr", OPT_NOATTR, '-', "Don't include any signed attributes"},
+ {"binary", OPT_BINARY, '-', "Don't translate message to text"},
+ {"signer", OPT_SIGNER, 's', "Signer certificate file"},
+ {"content", OPT_CONTENT, '<',
+ "Supply or override content for detached signature"},
+ {"nocerts", OPT_NOCERTS, '-',
+ "Don't include signers certificate when signing"},
+
+ OPT_SECTION("Verification/Decryption"),
+ {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"},
+ {"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"},
+
+ {"certfile", OPT_CERTFILE, '<', "Other certificates file"},
+ {"recip", OPT_RECIP, '<', "Recipient certificate file for decryption"},
+
+ OPT_SECTION("Email"),
+ {"to", OPT_TO, 's', "To address"},
+ {"from", OPT_FROM, 's', "From address"},
+ {"subject", OPT_SUBJECT, 's', "Subject"},
+ {"text", OPT_TEXT, '-', "Include or delete text MIME headers"},
+ {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"},
+
+ OPT_SECTION("Certificate chain"),
+ {"CApath", OPT_CAPATH, '/', "Trusted certificates directory"},
+ {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"},
+ {"CAstore", OPT_CASTORE, ':', "Trusted certificates store URI"},
+ {"no-CAfile", OPT_NOCAFILE, '-',
+ "Do not load the default certificates file"},
+ {"no-CApath", OPT_NOCAPATH, '-',
+ "Do not load certificates from the default certificates directory"},
+ {"no-CAstore", OPT_NOCASTORE, '-',
+ "Do not load certificates from the default certificates store"},
+ {"nochain", OPT_NOCHAIN, '-',
+ "set PKCS7_NOCHAIN so certificates contained in the message are not used as untrusted CAs" },
+ {"crlfeol", OPT_CRLFEOL, '-', "Use CRLF as EOL termination instead of CR only"},
+
+ OPT_R_OPTIONS,
+ OPT_V_OPTIONS,
+
+ OPT_PARAMETERS(),
+ {"cert", 0, 0, "Recipient certs, used when encrypting"},
+ {NULL}
+};
+
+int smime_main(int argc, char **argv)
+{
+ BIO *in = NULL, *out = NULL, *indata = NULL;
+ EVP_PKEY *key = NULL;
+ PKCS7 *p7 = NULL;
+ STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL;
+ STACK_OF(X509) *encerts = NULL, *other = NULL;
+ X509 *cert = NULL, *recip = NULL, *signer = NULL;
+ X509_STORE *store = NULL;
+ X509_VERIFY_PARAM *vpm = NULL;
+ const EVP_CIPHER *cipher = NULL;
+ const EVP_MD *sign_md = NULL;
+ const char *CAfile = NULL, *CApath = NULL, *CAstore = NULL, *prog = NULL;
+ char *certfile = NULL, *keyfile = NULL, *contfile = NULL;
+ char *infile = NULL, *outfile = NULL, *signerfile = NULL, *recipfile = NULL;
+ char *passinarg = NULL, *passin = NULL, *to = NULL, *from = NULL, *subject = NULL;
+ OPTION_CHOICE o;
+ int noCApath = 0, noCAfile = 0, noCAstore = 0;
+ int flags = PKCS7_DETACHED, operation = 0, ret = 0, indef = 0;
+ int informat = FORMAT_SMIME, outformat = FORMAT_SMIME, keyform =
+ FORMAT_PEM;
+ int vpmtouched = 0, rv = 0;
+ ENGINE *e = NULL;
+ const char *mime_eol = "\n";
+
+ if ((vpm = X509_VERIFY_PARAM_new()) == NULL)
+ return 1;
+
+ prog = opt_init(argc, argv, smime_options);
+ while ((o = opt_next()) != OPT_EOF) {
+ switch (o) {
+ case OPT_EOF:
+ case OPT_ERR:
+ opthelp:
+ BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
+ goto end;
+ case OPT_HELP:
+ opt_help(smime_options);
+ ret = 0;
+ goto end;
+ case OPT_INFORM:
+ if (!opt_format(opt_arg(), OPT_FMT_PDS, &informat))
+ goto opthelp;
+ break;
+ case OPT_IN:
+ infile = opt_arg();
+ break;
+ case OPT_OUTFORM:
+ if (!opt_format(opt_arg(), OPT_FMT_PDS, &outformat))
+ goto opthelp;
+ break;
+ case OPT_OUT:
+ outfile = opt_arg();
+ break;
+ case OPT_ENCRYPT:
+ operation = SMIME_ENCRYPT;
+ break;
+ case OPT_DECRYPT:
+ operation = SMIME_DECRYPT;
+ break;
+ case OPT_SIGN:
+ operation = SMIME_SIGN;
+ break;
+ case OPT_RESIGN:
+ operation = SMIME_RESIGN;
+ break;
+ case OPT_VERIFY:
+ operation = SMIME_VERIFY;
+ break;
+ case OPT_PK7OUT:
+ operation = SMIME_PK7OUT;
+ break;
+ case OPT_TEXT:
+ flags |= PKCS7_TEXT;
+ break;
+ case OPT_NOINTERN:
+ flags |= PKCS7_NOINTERN;
+ break;
+ case OPT_NOVERIFY:
+ flags |= PKCS7_NOVERIFY;
+ break;
+ case OPT_NOCHAIN:
+ flags |= PKCS7_NOCHAIN;
+ break;
+ case OPT_NOCERTS:
+ flags |= PKCS7_NOCERTS;
+ break;
+ case OPT_NOATTR:
+ flags |= PKCS7_NOATTR;
+ break;
+ case OPT_NODETACH:
+ flags &= ~PKCS7_DETACHED;
+ break;
+ case OPT_NOSMIMECAP:
+ flags |= PKCS7_NOSMIMECAP;
+ break;
+ case OPT_BINARY:
+ flags |= PKCS7_BINARY;
+ break;
+ case OPT_NOSIGS:
+ flags |= PKCS7_NOSIGS;
+ break;
+ case OPT_STREAM:
+ case OPT_INDEF:
+ indef = 1;
+ break;
+ case OPT_NOINDEF:
+ indef = 0;
+ break;
+ case OPT_CRLFEOL:
+ flags |= PKCS7_CRLFEOL;
+ mime_eol = "\r\n";
+ break;
+ case OPT_R_CASES:
+ if (!opt_rand(o))
+ goto end;
+ break;
+ case OPT_ENGINE:
+ e = setup_engine(opt_arg(), 0);
+ break;
+ case OPT_PASSIN:
+ passinarg = opt_arg();
+ break;
+ case OPT_TO:
+ to = opt_arg();
+ break;
+ case OPT_FROM:
+ from = opt_arg();
+ break;
+ case OPT_SUBJECT:
+ subject = opt_arg();
+ break;
+ case OPT_SIGNER:
+ /* If previous -signer argument add signer to list */
+ if (signerfile != NULL) {
+ if (sksigners == NULL
+ && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
+ goto end;
+ sk_OPENSSL_STRING_push(sksigners, signerfile);
+ if (keyfile == NULL)
+ keyfile = signerfile;
+ if (skkeys == NULL
+ && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
+ goto end;
+ sk_OPENSSL_STRING_push(skkeys, keyfile);
+ keyfile = NULL;
+ }
+ signerfile = opt_arg();
+ break;
+ case OPT_RECIP:
+ recipfile = opt_arg();
+ break;
+ case OPT_MD:
+ if (!opt_md(opt_arg(), &sign_md))
+ goto opthelp;
+ break;
+ case OPT_CIPHER:
+ if (!opt_cipher(opt_unknown(), &cipher))
+ goto opthelp;
+ break;
+ case OPT_INKEY:
+ /* If previous -inkey argument add signer to list */
+ if (keyfile != NULL) {
+ if (signerfile == NULL) {
+ BIO_printf(bio_err,
+ "%s: Must have -signer before -inkey\n", prog);
+ goto opthelp;
+ }
+ if (sksigners == NULL
+ && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
+ goto end;
+ sk_OPENSSL_STRING_push(sksigners, signerfile);
+ signerfile = NULL;
+ if (skkeys == NULL
+ && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
+ goto end;
+ sk_OPENSSL_STRING_push(skkeys, keyfile);
+ }
+ keyfile = opt_arg();
+ break;
+ case OPT_KEYFORM:
+ if (!opt_format(opt_arg(), OPT_FMT_ANY, &keyform))
+ goto opthelp;
+ break;
+ case OPT_CERTFILE:
+ certfile = opt_arg();
+ break;
+ case OPT_CAFILE:
+ CAfile = opt_arg();
+ break;
+ case OPT_CAPATH:
+ CApath = opt_arg();
+ break;
+ case OPT_CASTORE:
+ CAstore = opt_arg();
+ break;
+ case OPT_NOCAFILE:
+ noCAfile = 1;
+ break;
+ case OPT_NOCAPATH:
+ noCApath = 1;
+ break;
+ case OPT_NOCASTORE:
+ noCAstore = 1;
+ break;
+ case OPT_CONTENT:
+ contfile = opt_arg();
+ break;
+ case OPT_V_CASES:
+ if (!opt_verify(o, vpm))
+ goto opthelp;
+ vpmtouched++;
+ break;
+ }
+ }
+ argc = opt_num_rest();
+ argv = opt_rest();
+
+ if (!(operation & SMIME_SIGNERS) && (skkeys != NULL || sksigners != NULL)) {
+ BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
+ goto opthelp;
+ }
+
+ if (operation & SMIME_SIGNERS) {
+ /* Check to see if any final signer needs to be appended */
+ if (keyfile && !signerfile) {
+ BIO_puts(bio_err, "Illegal -inkey without -signer\n");
+ goto opthelp;
+ }
+ if (signerfile != NULL) {
+ if (sksigners == NULL
+ && (sksigners = sk_OPENSSL_STRING_new_null()) == NULL)
+ goto end;
+ sk_OPENSSL_STRING_push(sksigners, signerfile);
+ if (!skkeys && (skkeys = sk_OPENSSL_STRING_new_null()) == NULL)
+ goto end;
+ if (!keyfile)
+ keyfile = signerfile;
+ sk_OPENSSL_STRING_push(skkeys, keyfile);
+ }
+ if (sksigners == NULL) {
+ BIO_printf(bio_err, "No signer certificate specified\n");
+ goto opthelp;
+ }
+ signerfile = NULL;
+ keyfile = NULL;
+ } else if (operation == SMIME_DECRYPT) {
+ if (recipfile == NULL && keyfile == NULL) {
+ BIO_printf(bio_err,
+ "No recipient certificate or key specified\n");
+ goto opthelp;
+ }
+ } else if (operation == SMIME_ENCRYPT) {
+ if (argc == 0) {
+ BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
+ goto opthelp;
+ }
+ } else if (!operation) {
+ goto opthelp;
+ }
+
+ if (!app_passwd(passinarg, NULL, &passin, NULL)) {
+ BIO_printf(bio_err, "Error getting password\n");
+ goto end;
+ }
+
+ ret = 2;
+
+ if (!(operation & SMIME_SIGNERS))
+ flags &= ~PKCS7_DETACHED;
+
+ if (!(operation & SMIME_OP)) {
+ if (flags & PKCS7_BINARY)
+ outformat = FORMAT_BINARY;
+ }
+
+ if (!(operation & SMIME_IP)) {
+ if (flags & PKCS7_BINARY)
+ informat = FORMAT_BINARY;
+ }
+
+ if (operation == SMIME_ENCRYPT) {
+ if (cipher == NULL) {