apps_ui.c: Improve error handling and return value of setup_ui_method()
[openssl.git] / apps / cms.c
index 468820f3cf6ee97080061871c78e97f4d6bd71f4..d154f460b37d2c09d039f10b8d030f808e3a2d19 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2008-2020 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
 # include <openssl/x509v3.h>
 # include <openssl/cms.h>
 
+DEFINE_STACK_OF(X509)
+DEFINE_STACK_OF(CMS_SignerInfo)
+DEFINE_STACK_OF(GENERAL_NAME)
+DEFINE_STACK_OF(GENERAL_NAMES)
+DEFINE_STACK_OF_STRING()
+
 static int save_certs(char *signerfile, STACK_OF(X509) *signers);
 static int cms_cb(int ok, X509_STORE_CTX *ctx);
 static void receipt_request_print(CMS_ContentInfo *cms);
-static CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING)
-                                                *rr_to, int rr_allorfirst, STACK_OF(OPENSSL_STRING)
-                                                *rr_from);
+static CMS_ReceiptRequest *make_receipt_request(
+    STACK_OF(OPENSSL_STRING) *rr_to, int rr_allorfirst,
+    STACK_OF(OPENSSL_STRING) *rr_from, OPENSSL_CTX *libctx, const char *propq);
 static int cms_set_pkey_param(EVP_PKEY_CTX *pctx,
                               STACK_OF(OPENSSL_STRING) *param);
 
@@ -76,28 +82,51 @@ typedef enum OPTION_choice {
     OPT_NOINDEF, OPT_CRLFEOL, OPT_NOOUT, OPT_RR_PRINT,
     OPT_RR_ALL, OPT_RR_FIRST, OPT_RCTFORM, OPT_CERTFILE, OPT_CAFILE,
     OPT_CAPATH, OPT_CASTORE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_NOCASTORE,
-    OPT_CONTENT, OPT_PRINT,
+    OPT_CONTENT, OPT_PRINT, OPT_NAMEOPT,
     OPT_SECRETKEY, OPT_SECRETKEYID, OPT_PWRI_PASSWORD, OPT_ECONTENT_TYPE,
     OPT_PASSIN, OPT_TO, OPT_FROM, OPT_SUBJECT, OPT_SIGNER, OPT_RECIP,
     OPT_CERTSOUT, OPT_MD, OPT_INKEY, OPT_KEYFORM, OPT_KEYOPT, OPT_RR_FROM,
     OPT_RR_TO, OPT_AES128_WRAP, OPT_AES192_WRAP, OPT_AES256_WRAP,
-    OPT_3DES_WRAP, OPT_ENGINE,
+    OPT_3DES_WRAP, OPT_WRAP, OPT_ENGINE,
     OPT_R_ENUM,
+    OPT_PROV_ENUM, OPT_CONFIG,
     OPT_V_ENUM,
-    OPT_CIPHER
+    OPT_CIPHER,
+    OPT_ORIGINATOR
 } OPTION_CHOICE;
 
 const OPTIONS cms_options[] = {
-    {OPT_HELP_STR, 1, '-', "Usage: %s [options] cert.pem...\n"},
-    {OPT_HELP_STR, 1, '-',
-        "  cert.pem... recipient certs for encryption\n"},
-    {OPT_HELP_STR, 1, '-', "Valid options are:\n"},
+    {OPT_HELP_STR, 1, '-', "Usage: %s [options] [cert...]\n"},
+
+    OPT_SECTION("General"),
     {"help", OPT_HELP, '-', "Display this summary"},
     {"inform", OPT_INFORM, 'c', "Input format SMIME (default), PEM or DER"},
     {"outform", OPT_OUTFORM, 'c',
      "Output format SMIME (default), PEM or DER"},
     {"in", OPT_IN, '<', "Input file"},
     {"out", OPT_OUT, '>', "Output file"},
+    {"debug_decrypt", OPT_DEBUG_DECRYPT, '-',
+        "Disable MMA protection and return an error if no recipient found"
+        " (see documentation)"},
+    {"stream", OPT_INDEF, '-', "Enable CMS streaming"},
+    {"indef", OPT_INDEF, '-', "Same as -stream"},
+    {"noindef", OPT_NOINDEF, '-', "Disable CMS streaming"},
+    {"crlfeol", OPT_CRLFEOL, '-', "Use CRLF as EOL termination instead of CR only" },
+    {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"},
+    {"CApath", OPT_CAPATH, '/', "trusted certificates directory"},
+    {"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"},
+# ifndef OPENSSL_NO_ENGINE
+    {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"},
+# endif
+    OPT_CONFIG_OPTION,
+
+    OPT_SECTION("Action"),
     {"encrypt", OPT_ENCRYPT, '-', "Encrypt message"},
     {"decrypt", OPT_DECRYPT, '-', "Decrypt encrypted message"},
     {"sign", OPT_SIGN, '-', "Sign message"},
@@ -109,45 +138,42 @@ const OPTIONS cms_options[] = {
         "Exit non-zero on verification failure"},
     {"verify_receipt", OPT_VERIFY_RECEIPT, '<',
         "Verify receipts; exit if receipt signatures do not verify"},
-    {"cmsout", OPT_CMSOUT, '-', "Output CMS structure"},
-    {"data_out", OPT_DATA_OUT, '-', "Copy CMS \"Data\" object to output"},
-    {"data_create", OPT_DATA_CREATE, '-', "Create a CMS \"Data\" object"},
     {"digest_verify", OPT_DIGEST_VERIFY, '-',
         "Verify a CMS \"DigestedData\" object and output it"},
     {"digest_create", OPT_DIGEST_CREATE, '-',
         "Create a CMS \"DigestedData\" object"},
     {"compress", OPT_COMPRESS, '-', "Create a CMS \"CompressedData\" object"},
-    {"uncompress", OPT_UNCOMPRESS, '-', "Uncompress a CMS \"CompressedData\" object"},
+    {"uncompress", OPT_UNCOMPRESS, '-',
+        "Uncompress a CMS \"CompressedData\" object"},
     {"EncryptedData_decrypt", OPT_ED_DECRYPT, '-',
         "Decrypt CMS \"EncryptedData\" object using symmetric key"},
     {"EncryptedData_encrypt", OPT_ED_ENCRYPT, '-',
         "Create CMS \"EncryptedData\" object using symmetric key"},
-    {"debug_decrypt", OPT_DEBUG_DECRYPT, '-',
-        "Disable MMA protection and return an error if no recipient found"
-        " (see documentation)"},
+    {"data_out", OPT_DATA_OUT, '-', "Copy CMS \"Data\" object to output"},
+    {"data_create", OPT_DATA_CREATE, '-', "Create a CMS \"Data\" object"},
+    {"cmsout", OPT_CMSOUT, '-', "Output CMS structure"},
+    {"no_content_verify", OPT_NO_CONTENT_VERIFY, '-',
+        "Do not verify signed content signatures"},
+    {"no_attr_verify", OPT_NO_ATTR_VERIFY, '-',
+        "Do not verify signed attribute signatures"},
+    {"nointern", OPT_NOINTERN, '-',
+        "Don't search certificates in message for signer"},
+    {"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"},
+
+    OPT_SECTION("Formatting"),
     {"text", OPT_TEXT, '-', "Include or delete text MIME headers"},
     {"asciicrlf", OPT_ASCIICRLF, '-',
         "Perform CRLF canonicalisation when signing"},
-    {"nointern", OPT_NOINTERN, '-',
-     "Don't search certificates in message for signer"},
-    {"noverify", OPT_NOVERIFY, '-', "Don't verify signers certificate"},
-    {"nocerts", OPT_NOCERTS, '-',
-     "Don't include signers certificate when signing"},
-    {"noattr", OPT_NOATTR, '-', "Don't include any signed attributes"},
     {"nodetach", OPT_NODETACH, '-', "Use opaque signing"},
     {"nosmimecap", OPT_NOSMIMECAP, '-', "Omit the SMIMECapabilities attribute"},
+    {"noattr", OPT_NOATTR, '-', "Don't include any signed attributes"},
     {"binary", OPT_BINARY, '-', "Don't translate message to text"},
     {"keyid", OPT_KEYID, '-', "Use subject key identifier"},
     {"nosigs", OPT_NOSIGS, '-', "Don't verify message signature"},
-    {"no_content_verify", OPT_NO_CONTENT_VERIFY, '-',
-        "Do not verify signed content signatures"},
-    {"no_attr_verify", OPT_NO_ATTR_VERIFY, '-',
-        "Do not verify signed attribute signatures"},
-    {"stream", OPT_INDEF, '-', "Enable CMS streaming"},
-    {"indef", OPT_INDEF, '-', "Same as -stream"},
-    {"noindef", OPT_NOINDEF, '-', "Disable CMS streaming"},
-    {"crlfeol", OPT_CRLFEOL, '-', "Use CRLF as EOL termination instead of CR only" },
-    {"noout", OPT_NOOUT, '-', "For the -cmsout operation do not output the parsed CMS structure"},
+    {"nocerts", OPT_NOCERTS, '-',
+     "Don't include signers certificate when signing"},
+    {"noout", OPT_NOOUT, '-',
+        "For the -cmsout operation do not output the parsed CMS structure"},
     {"receipt_request_print", OPT_RR_PRINT, '-', "Print CMS Receipt Request" },
     {"receipt_request_all", OPT_RR_ALL, '-',
         "When signing, create a receipt request for all recipients"},
@@ -155,59 +181,100 @@ const OPTIONS cms_options[] = {
         "When signing, create a receipt request for first recipient"},
     {"rctform", OPT_RCTFORM, 'F', "Receipt file format"},
     {"certfile", OPT_CERTFILE, '<', "Other certificates file"},
-    {"CAfile", OPT_CAFILE, '<', "Trusted certificates file"},
-    {"CApath", OPT_CAPATH, '/', "trusted certificates directory"},
-    {"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"},
     {"content", OPT_CONTENT, '<',
      "Supply or override content for detached signature"},
     {"print", OPT_PRINT, '-',
      "For the -cmsout operation print out all fields of the CMS structure"},
+    {"nameopt", OPT_NAMEOPT, 's',
+     "For the -print option specifies various strings printing options"},
+    {"certsout", OPT_CERTSOUT, '>', "Certificate output file"},
+
+    OPT_SECTION("Keying"),
     {"secretkey", OPT_SECRETKEY, 's',
         "Use specified hex-encoded key to decrypt/encrypt recipients or content"},
     {"secretkeyid", OPT_SECRETKEYID, 's',
         "Identity of the -secretkey for CMS \"KEKRecipientInfo\" object"},
     {"pwri_password", OPT_PWRI_PASSWORD, 's',
         "Specific password for recipient"},
-    {"econtent_type", OPT_ECONTENT_TYPE, 's', "OID for external content"},
     {"passin", OPT_PASSIN, 's', "Input file pass phrase source"},
+    {"inkey", OPT_INKEY, 's',
+     "Input private key (if not signer or recipient)"},
+    {"keyform", OPT_KEYFORM, 'f', "Input private key format (ENGINE, other values ignored)"},
+    {"keyopt", OPT_KEYOPT, 's', "Set public key parameters as n:v pairs"},
+
+    OPT_SECTION("Mail header"),
+    {"econtent_type", OPT_ECONTENT_TYPE, 's', "OID for external content"},
     {"to", OPT_TO, 's', "To address"},
     {"from", OPT_FROM, 's', "From address"},
     {"subject", OPT_SUBJECT, 's', "Subject"},
     {"signer", OPT_SIGNER, 's', "Signer certificate file"},
+    {"originator", OPT_ORIGINATOR, 's', "Originator certificate file"},
     {"recip", OPT_RECIP, '<', "Recipient cert file for decryption"},
-    {"certsout", OPT_CERTSOUT, '>', "Certificate output file"},
-    {"md", OPT_MD, 's', "Digest algorithm to use when signing or resigning"},
-    {"inkey", OPT_INKEY, 's',
-     "Input private key (if not signer or recipient)"},
-    {"keyform", OPT_KEYFORM, 'f', "Input private key format (PEM or ENGINE)"},
-    {"keyopt", OPT_KEYOPT, 's', "Set public key parameters as n:v pairs"},
     {"receipt_request_from", OPT_RR_FROM, 's',
         "Create signed receipt request with specified email address"},
     {"receipt_request_to", OPT_RR_TO, 's',
         "Create signed receipt targeted to specified address"},
+
+    OPT_SECTION("Encryption"),
+    {"md", OPT_MD, 's', "Digest algorithm to use when signing or resigning"},
     {"", OPT_CIPHER, '-', "Any supported cipher"},
-    OPT_R_OPTIONS,
-    OPT_V_OPTIONS,
+
+    OPT_SECTION("Key-wrapping"),
     {"aes128-wrap", OPT_AES128_WRAP, '-', "Use AES128 to wrap key"},
     {"aes192-wrap", OPT_AES192_WRAP, '-', "Use AES192 to wrap key"},
     {"aes256-wrap", OPT_AES256_WRAP, '-', "Use AES256 to wrap key"},
 # ifndef OPENSSL_NO_DES
     {"des3-wrap", OPT_3DES_WRAP, '-', "Use 3DES-EDE to wrap key"},
 # endif
-# ifndef OPENSSL_NO_ENGINE
-    {"engine", OPT_ENGINE, 's', "Use engine e, possibly a hardware device"},
-# endif
+    {"wrap", OPT_WRAP, 's', "Any wrap cipher to wrap key"},
+
+    OPT_R_OPTIONS,
+    OPT_V_OPTIONS,
+    OPT_PROV_OPTIONS,
+
+    OPT_PARAMETERS(),
+    {"cert", 0, 0, "Recipient certs (optional; used only when encrypting)"},
     {NULL}
 };
 
+static CMS_ContentInfo *load_content_info(int informat, BIO *in, BIO **indata,
+                                          const char *name,
+                                          OPENSSL_CTX *libctx, const char *propq)
+{
+    CMS_ContentInfo *ret, *ci;
+
+    ret = CMS_ContentInfo_new_with_libctx(libctx, propq);
+    if (ret == NULL) {
+        BIO_printf(bio_err, "Error allocating CMS_contentinfo\n");
+        return NULL;
+    }
+    switch (informat) {
+    case FORMAT_SMIME:
+        ci = SMIME_read_CMS_ex(in, indata, &ret);
+        break;
+    case FORMAT_PEM:
+        ci = PEM_read_bio_CMS(in, &ret, NULL, NULL);
+        break;
+    case FORMAT_ASN1:
+        ci = d2i_CMS_bio(in, &ret);
+        break;
+    default:
+        BIO_printf(bio_err, "Bad input format for %s\n", name);
+        goto err;
+    }
+    if (ci == NULL) {
+        BIO_printf(bio_err, "Error reading %s Content Info\n", name);
+        goto err;
+    }
+    return ret;
+err:
+    CMS_ContentInfo_free(ret);
+    return NULL;
+}
+
 int cms_main(int argc, char **argv)
 {
+    CONF *conf = NULL;
     ASN1_OBJECT *econtent_type = NULL;
     BIO *in = NULL, *out = NULL, *indata = NULL, *rctin = NULL;
     CMS_ContentInfo *cms = NULL, *rcms = NULL;
@@ -219,7 +286,7 @@ int cms_main(int argc, char **argv)
     STACK_OF(OPENSSL_STRING) *rr_to = NULL, *rr_from = NULL;
     STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL;
     STACK_OF(X509) *encerts = NULL, *other = NULL;
-    X509 *cert = NULL, *recip = NULL, *signer = NULL;
+    X509 *cert = NULL, *recip = NULL, *signer = NULL, *originator = NULL;
     X509_STORE *store = NULL;
     X509_VERIFY_PARAM *vpm = NULL;
     char *certfile = NULL, *keyfile = NULL, *contfile = NULL;
@@ -227,7 +294,7 @@ int cms_main(int argc, char **argv)
     char *certsoutfile = NULL;
     int noCAfile = 0, noCApath = 0, noCAstore = 0;
     char *infile = NULL, *outfile = NULL, *rctfile = NULL;
-    char *passinarg = NULL, *passin = NULL, *signerfile = NULL, *recipfile = NULL;
+    char *passinarg = NULL, *passin = NULL, *signerfile = NULL, *originatorfile = NULL, *recipfile = NULL;
     char *to = NULL, *from = NULL, *subject = NULL, *prog;
     cms_key_param *key_first = NULL, *key_param = NULL;
     int flags = CMS_DETACHED, noout = 0, print = 0, keyidx = -1, vpmtouched = 0;
@@ -240,6 +307,8 @@ int cms_main(int argc, char **argv)
     long ltmp;
     const char *mime_eol = "\n";
     OPTION_CHOICE o;
+    OPENSSL_CTX *libctx = app_get0_libctx();
+    const char *propq = app_get0_propq();
 
     if ((vpm = X509_VERIFY_PARAM_new()) == NULL)
         return 1;
@@ -387,14 +456,14 @@ int cms_main(int argc, char **argv)
             rr_allorfirst = 1;
             break;
         case OPT_RCTFORM:
-            if (rctformat == FORMAT_SMIME)
-                rcms = SMIME_read_CMS(rctin, NULL);
-            else if (rctformat == FORMAT_PEM)
-                rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL);
-            else if (rctformat == FORMAT_ASN1)
+            if (rctformat == FORMAT_ASN1) {
                 if (!opt_format(opt_arg(),
                                 OPT_FMT_PEMDER | OPT_FMT_SMIME, &rctformat))
                     goto opthelp;
+            } else {
+                rcms = load_content_info(rctformat, rctin, NULL, "recipient",
+                                         libctx, propq);
+            }
             break;
         case OPT_CERTFILE:
             certfile = opt_arg();
@@ -438,6 +507,10 @@ int cms_main(int argc, char **argv)
         case OPT_PRINT:
             noout = print = 1;
             break;
+        case OPT_NAMEOPT:
+            if (!set_nameopt(opt_arg()))
+                goto opthelp;
+            break;
         case OPT_SECRETKEY:
             if (secret_key != NULL) {
                 BIO_printf(bio_err, "Invalid key (supplied twice) %s\n",
@@ -518,6 +591,9 @@ int cms_main(int argc, char **argv)
             }
             signerfile = opt_arg();
             break;
+        case OPT_ORIGINATOR:
+             originatorfile = opt_arg();
+             break;
         case OPT_INKEY:
             /* If previous -inkey argument add signer to list */
             if (keyfile != NULL) {
@@ -545,7 +621,7 @@ int cms_main(int argc, char **argv)
             if (operation == SMIME_ENCRYPT) {
                 if (encerts == NULL && (encerts = sk_X509_new_null()) == NULL)
                     goto end;
-                cert = load_cert(opt_arg(), FORMAT_PEM,
+                cert = load_cert(opt_arg(), FORMAT_UNDEF,
                                  "recipient certificate file");
                 if (cert == NULL)
                     goto end;
@@ -598,6 +674,15 @@ int cms_main(int argc, char **argv)
             if (!opt_rand(o))
                 goto end;
             break;
+        case OPT_PROV_CASES:
+            if (!opt_provider(o))
+                goto end;
+            break;
+        case OPT_CONFIG:
+            conf = app_load_config_modules(opt_arg());
+            if (conf == NULL)
+                goto end;
+            break;
         case OPT_3DES_WRAP:
 # ifndef OPENSSL_NO_DES
             wrap_cipher = EVP_des_ede3_wrap();
@@ -612,6 +697,10 @@ int cms_main(int argc, char **argv)
         case OPT_AES256_WRAP:
             wrap_cipher = EVP_aes_256_wrap();
             break;
+        case OPT_WRAP:
+            if (!opt_cipher(opt_unknown(), &wrap_cipher))
+                goto end;
+            break;
         }
     }
     argc = opt_num_rest();
@@ -631,12 +720,18 @@ int cms_main(int argc, char **argv)
         goto opthelp;
     }
 
-    if (flags & CMS_CADES) {
-        if (flags & CMS_NOATTR) {
+    if ((flags & CMS_CADES) != 0) {
+        if ((flags & CMS_NOATTR) != 0) {
             BIO_puts(bio_err, "Incompatible options: "
                      "CAdES required signed attributes\n");
             goto opthelp;
         }
+        if (operation == SMIME_VERIFY
+                && (flags & (CMS_NO_SIGNER_CERT_VERIFY | CMS_NO_ATTR_VERIFY)) != 0) {
+            BIO_puts(bio_err, "Incompatible options: CAdES validation require"
+                     " certs and signed attributes validations\n");
+            goto opthelp;
+        }
     }
 
     if (operation & SMIME_SIGNERS) {
@@ -717,7 +812,7 @@ int cms_main(int argc, char **argv)
             if ((encerts = sk_X509_new_null()) == NULL)
                 goto end;
         while (*argv) {
-            if ((cert = load_cert(*argv, FORMAT_PEM,
+            if ((cert = load_cert(*argv, FORMAT_UNDEF,
                                   "recipient certificate file")) == NULL)
                 goto end;
             sk_X509_push(encerts, cert);
@@ -727,30 +822,37 @@ int cms_main(int argc, char **argv)
     }
 
     if (certfile != NULL) {
-        if (!load_certs(certfile, &other, FORMAT_PEM, NULL,
-                        "certificate file")) {
+        if (!load_certs(certfile, &other, NULL, "certificate file")) {
             ERR_print_errors(bio_err);
             goto end;
         }
     }
 
     if (recipfile != NULL && (operation == SMIME_DECRYPT)) {
-        if ((recip = load_cert(recipfile, FORMAT_PEM,
+        if ((recip = load_cert(recipfile, FORMAT_UNDEF,
                                "recipient certificate file")) == NULL) {
             ERR_print_errors(bio_err);
             goto end;
         }
     }
 
+    if (originatorfile != NULL) {
+        if ((originator = load_cert(originatorfile, FORMAT_UNDEF,
+                                    "originator certificate file")) == NULL) {
+             ERR_print_errors(bio_err);
+             goto end;
+        }
+    }
+
     if (operation == SMIME_SIGN_RECEIPT) {
-        if ((signer = load_cert(signerfile, FORMAT_PEM,
+        if ((signer = load_cert(signerfile, FORMAT_UNDEF,
                                 "receipt signer certificate file")) == NULL) {
             ERR_print_errors(bio_err);
             goto end;
         }
     }
 
-    if (operation == SMIME_DECRYPT) {
+    if ((operation == SMIME_DECRYPT) || (operation == SMIME_ENCRYPT)) {
         if (keyfile == NULL)
             keyfile = recipfile;
     } else if ((operation == SMIME_SIGN) || (operation == SMIME_SIGN_RECEIPT)) {
@@ -764,6 +866,13 @@ int cms_main(int argc, char **argv)
         key = load_key(keyfile, keyform, 0, passin, e, "signing key file");
         if (key == NULL)
             goto end;
+
+        /*
+         * TODO: Remove this when CMS has full support for provider-native
+         * EVP_PKEYs
+         */
+        if (EVP_PKEY_get0(key) == NULL)
+            goto end;
     }
 
     in = bio_open_default(infile, 'r', informat);
@@ -771,21 +880,9 @@ int cms_main(int argc, char **argv)
         goto end;
 
     if (operation & SMIME_IP) {
-        if (informat == FORMAT_SMIME) {
-            cms = SMIME_read_CMS(in, &indata);
-        } else if (informat == FORMAT_PEM) {
-            cms = PEM_read_bio_CMS(in, NULL, NULL, NULL);
-        } else if (informat == FORMAT_ASN1) {
-            cms = d2i_CMS_bio(in, NULL);
-        } else {
-            BIO_printf(bio_err, "Bad input format for CMS file\n");
-            goto end;
-        }
-
-        if (cms == NULL) {
-            BIO_printf(bio_err, "Error reading S/MIME message\n");
+        cms = load_content_info(informat, in, &indata, "SMIME", libctx, propq);
+        if (cms == NULL)
             goto end;
-        }
         if (contfile != NULL) {
             BIO_free(indata);
             if ((indata = BIO_new_file(contfile, "rb")) == NULL) {
@@ -813,21 +910,10 @@ int cms_main(int argc, char **argv)
             goto end;
         }
 
-        if (rctformat == FORMAT_SMIME) {
-            rcms = SMIME_read_CMS(rctin, NULL);
-        } else if (rctformat == FORMAT_PEM) {
-            rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL);
-        } else if (rctformat == FORMAT_ASN1) {
-            rcms = d2i_CMS_bio(rctin, NULL);
-        } else {
-            BIO_printf(bio_err, "Bad input format for receipt\n");
-            goto end;
-        }
-
-        if (rcms == NULL) {
-            BIO_printf(bio_err, "Error reading receipt\n");
+        rcms = load_content_info(rctformat, rctin, NULL, "recipient", libctx,
+                                 propq);
+        if (rcms == NULL)
             goto end;
-        }
     }
 
     out = bio_open_default(outfile, 'w', outformat);
@@ -846,37 +932,46 @@ int cms_main(int argc, char **argv)
     ret = 3;
 
     if (operation == SMIME_DATA_CREATE) {
-        cms = CMS_data_create(in, flags);
+        cms = CMS_data_create_with_libctx(in, flags, libctx, propq);
     } else if (operation == SMIME_DIGEST_CREATE) {
-        cms = CMS_digest_create(in, sign_md, flags);
+        cms = CMS_digest_create_with_libctx(in, sign_md, flags, libctx, propq);
     } else if (operation == SMIME_COMPRESS) {
         cms = CMS_compress(in, -1, flags);
     } else if (operation == SMIME_ENCRYPT) {
         int i;
         flags |= CMS_PARTIAL;
-        cms = CMS_encrypt(NULL, in, cipher, flags);
+        cms = CMS_encrypt_with_libctx(NULL, in, cipher, flags, libctx, propq);
         if (cms == NULL)
             goto end;
         for (i = 0; i < sk_X509_num(encerts); i++) {
             CMS_RecipientInfo *ri;
             cms_key_param *kparam;
-            int tflags = flags;
+            int tflags = flags | CMS_KEY_PARAM; /* This flag enforces allocating the EVP_PKEY_CTX for the recipient here */
+            EVP_PKEY_CTX *pctx;
             X509 *x = sk_X509_value(encerts, i);
+            int res;
+
             for (kparam = key_first; kparam; kparam = kparam->next) {
                 if (kparam->idx == i) {
-                    tflags |= CMS_KEY_PARAM;
                     break;
                 }
             }
-            ri = CMS_add1_recipient_cert(cms, x, tflags);
+            ri = CMS_add1_recipient(cms, x, key, originator, tflags);
             if (ri == NULL)
                 goto end;
+
+            pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
             if (kparam != NULL) {
-                EVP_PKEY_CTX *pctx;
-                pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
                 if (!cms_set_pkey_param(pctx, kparam->param))
                     goto end;
             }
+
+            res = EVP_PKEY_CTX_ctrl(pctx, -1, -1,
+                                    EVP_PKEY_CTRL_CIPHER,
+                                    EVP_CIPHER_nid(cipher), NULL);
+            if (res <= 0 && res != -2)
+                goto end;
+
             if (CMS_RecipientInfo_type(ri) == CMS_RECIPINFO_AGREE
                 && wrap_cipher) {
                 EVP_CIPHER_CTX *wctx;
@@ -910,8 +1005,9 @@ int cms_main(int argc, char **argv)
                 goto end;
         }
     } else if (operation == SMIME_ENCRYPTED_ENCRYPT) {
-        cms = CMS_EncryptedData_encrypt(in, cipher,
-                                        secret_key, secret_keylen, flags);
+        cms = CMS_EncryptedData_encrypt_with_libctx(in, cipher, secret_key,
+                                                    secret_keylen, flags,
+                                                    libctx, propq);
 
     } else if (operation == SMIME_SIGN_RECEIPT) {
         CMS_ContentInfo *srcms = NULL;
@@ -939,14 +1035,15 @@ int cms_main(int argc, char **argv)
                     flags |= CMS_STREAM;
             }
             flags |= CMS_PARTIAL;
-            cms = CMS_sign(NULL, NULL, other, in, flags);
+            cms = CMS_sign_with_libctx(NULL, NULL, other, in, flags, libctx, propq);
             if (cms == NULL)
                 goto end;
             if (econtent_type != NULL)
                 CMS_set1_eContentType(cms, econtent_type);
 
             if (rr_to != NULL) {
-                rr = make_receipt_request(rr_to, rr_allorfirst, rr_from);
+                rr = make_receipt_request(rr_to, rr_allorfirst, rr_from, libctx,
+                                          propq);
                 if (rr == NULL) {
                     BIO_puts(bio_err,
                              "Signed Receipt Request Creation Error\n");
@@ -963,7 +1060,8 @@ int cms_main(int argc, char **argv)
             signerfile = sk_OPENSSL_STRING_value(sksigners, i);
             keyfile = sk_OPENSSL_STRING_value(skkeys, i);
 
-            signer = load_cert(signerfile, FORMAT_PEM, "signer certificate");
+            signer = load_cert(signerfile, FORMAT_UNDEF,
+                               "signer certificate");
             if (signer == NULL) {
                 ret = 2;
                 goto end;
@@ -973,6 +1071,14 @@ int cms_main(int argc, char **argv)
                 ret = 2;
                 goto end;
             }
+
+            /*
+             * TODO: Remove this when CMS has full support for provider-native
+             * EVP_PKEYs
+             */
+            if (EVP_PKEY_get0(key) == NULL)
+                goto end;
+
             for (kparam = key_first; kparam; kparam = kparam->next) {
                 if (kparam->idx == i) {
                     tflags |= CMS_KEY_PARAM;
@@ -1022,7 +1128,7 @@ int cms_main(int argc, char **argv)
         }
 
         if (key != NULL) {
-            if (!CMS_decrypt_set1_pkey(cms, key, recip)) {
+            if (!CMS_decrypt_set1_pkey_and_peer(cms, key, recip, originator)) {
                 BIO_puts(bio_err, "Error decrypting CMS using private key\n");
                 goto end;
             }
@@ -1058,7 +1164,8 @@ int cms_main(int argc, char **argv)
             goto end;
     } else if (operation == SMIME_VERIFY) {
         if (CMS_verify(cms, other, store, indata, out, flags) > 0) {
-            BIO_printf(bio_err, "Verification successful\n");
+            BIO_printf(bio_err, "%s Verification successful\n",
+                       (flags & CMS_CADES) ? "CAdES" : "CMS");
         } else {
             BIO_printf(bio_err, "Verification failure\n");
             if (verify_retcode)
@@ -1088,8 +1195,19 @@ int cms_main(int argc, char **argv)
         }
     } else {
         if (noout) {
-            if (print)
-                CMS_ContentInfo_print_ctx(out, cms, 0, NULL);
+            if (print) {
+                ASN1_PCTX *pctx = NULL;
+                if (get_nameopt() != XN_FLAG_ONELINE) {
+                    pctx = ASN1_PCTX_new();
+                    if (pctx != NULL) { /* Print anyway if malloc failed */
+                        ASN1_PCTX_set_flags(pctx, ASN1_PCTX_FLAGS_SHOW_ABSENT);
+                        ASN1_PCTX_set_str_flags(pctx, get_nameopt());
+                        ASN1_PCTX_set_nm_flags(pctx, get_nameopt());
+                    }
+                }
+                CMS_ContentInfo_print_ctx(out, cms, 0, pctx);
+                ASN1_PCTX_free(pctx);
+            }
         } else if (outformat == FORMAT_SMIME) {
             if (to)
                 BIO_printf(out, "To: %s%s", to, mime_eol);
@@ -1150,6 +1268,7 @@ int cms_main(int argc, char **argv)
     BIO_free(indata);
     BIO_free_all(out);
     OPENSSL_free(passin);
+    NCONF_free(conf);
     return ret;
 }
 
@@ -1286,9 +1405,10 @@ static STACK_OF(GENERAL_NAMES) *make_names_stack(STACK_OF(OPENSSL_STRING) *ns)
     return NULL;
 }
 
-static CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING)
-                                                *rr_to, int rr_allorfirst, STACK_OF(OPENSSL_STRING)
-                                                *rr_from)
+static CMS_ReceiptRequest *make_receipt_request(
+   STACK_OF(OPENSSL_STRING) *rr_to, int rr_allorfirst,
+   STACK_OF(OPENSSL_STRING) *rr_from,
+   OPENSSL_CTX *libctx, const char *propq)
 {
     STACK_OF(GENERAL_NAMES) *rct_to = NULL, *rct_from = NULL;
     CMS_ReceiptRequest *rr;
@@ -1302,8 +1422,8 @@ static CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING)
     } else {
         rct_from = NULL;
     }
-    rr = CMS_ReceiptRequest_create0(NULL, -1, rr_allorfirst, rct_from,
-                                    rct_to);
+    rr = CMS_ReceiptRequest_create0_with_libctx(NULL, -1, rr_allorfirst,
+                                                rct_from, rct_to, libctx, propq);
     return rr;
  err:
     sk_GENERAL_NAMES_pop_free(rct_to, GENERAL_NAMES_free);