add OSSL_STACK_OF_X509_free() for commonly used pattern
[openssl.git] / crypto / cms / cms_smime.c
index 5b55f055f76063398e8e1bc4061e6d4af5ab1b6d..b82eee32cb2157bfbac75cb4ec8022ff458a4d17 100644 (file)
@@ -1,55 +1,10 @@
-/* crypto/cms/cms_smime.c */
 /*
- * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project.
- */
-/* ====================================================================
- * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
+ * Copyright 2008-2021 The OpenSSL Project Authors. All Rights Reserved.
  *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
+ * 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
  */
 
 #include "internal/cryptlib.h"
 #include <openssl/x509v3.h>
 #include <openssl/err.h>
 #include <openssl/cms.h>
-#include "cms_lcl.h"
-#include "internal/asn1_int.h"
+#include "cms_local.h"
+#include "crypto/asn1.h"
 
 static BIO *cms_get_text_bio(BIO *out, unsigned int flags)
 {
     BIO *rbio;
+
     if (out == NULL)
         rbio = BIO_new(BIO_s_null());
     else if (flags & CMS_TEXT) {
@@ -83,7 +39,7 @@ static int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
     tmpout = cms_get_text_bio(out, flags);
 
     if (tmpout == NULL) {
-        CMSerr(CMS_F_CMS_COPY_CONTENT, ERR_R_MALLOC_FAILURE);
+        ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
         goto err;
     }
 
@@ -100,19 +56,18 @@ static int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
             break;
         }
 
-        if (tmpout && (BIO_write(tmpout, buf, i) != i))
+        if (tmpout != NULL && (BIO_write(tmpout, buf, i) != i))
             goto err;
     }
 
     if (flags & CMS_TEXT) {
         if (!SMIME_text(tmpout, out)) {
-            CMSerr(CMS_F_CMS_COPY_CONTENT, CMS_R_SMIME_TEXT_ERROR);
+            ERR_raise(ERR_LIB_CMS, CMS_R_SMIME_TEXT_ERROR);
             goto err;
         }
     }
 
     r = 1;
-
  err:
     if (tmpout != out)
         BIO_free(tmpout);
@@ -123,8 +78,9 @@ static int cms_copy_content(BIO *out, BIO *in, unsigned int flags)
 static int check_content(CMS_ContentInfo *cms)
 {
     ASN1_OCTET_STRING **pos = CMS_get0_content(cms);
-    if (!pos || !*pos) {
-        CMSerr(CMS_F_CHECK_CONTENT, CMS_R_NO_CONTENT);
+
+    if (pos == NULL || *pos == NULL) {
+        ERR_raise(ERR_LIB_CMS, CMS_R_NO_CONTENT);
         return 0;
     }
     return 1;
@@ -132,80 +88,95 @@ static int check_content(CMS_ContentInfo *cms)
 
 static void do_free_upto(BIO *f, BIO *upto)
 {
-    if (upto) {
+    if (upto != NULL) {
         BIO *tbio;
+
         do {
             tbio = BIO_pop(f);
             BIO_free(f);
             f = tbio;
-        }
-        while (f && f != upto);
-    } else
+        } while (f != NULL && f != upto);
+    } else {
         BIO_free_all(f);
+    }
 }
 
 int CMS_data(CMS_ContentInfo *cms, BIO *out, unsigned int flags)
 {
     BIO *cont;
     int r;
+
     if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_data) {
-        CMSerr(CMS_F_CMS_DATA, CMS_R_TYPE_NOT_DATA);
+        ERR_raise(ERR_LIB_CMS, CMS_R_TYPE_NOT_DATA);
         return 0;
     }
     cont = CMS_dataInit(cms, NULL);
-    if (!cont)
+    if (cont == NULL)
         return 0;
     r = cms_copy_content(out, cont, flags);
     BIO_free_all(cont);
     return r;
 }
 
-CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags)
+CMS_ContentInfo *CMS_data_create_ex(BIO *in, unsigned int flags,
+                                    OSSL_LIB_CTX *libctx, const char *propq)
 {
-    CMS_ContentInfo *cms;
-    cms = cms_Data_create();
-    if (!cms)
+    CMS_ContentInfo *cms = ossl_cms_Data_create(libctx, propq);
+
+    if (cms == NULL)
         return NULL;
 
     if ((flags & CMS_STREAM) || CMS_final(cms, in, NULL, flags))
         return cms;
 
     CMS_ContentInfo_free(cms);
-
     return NULL;
 }
 
+CMS_ContentInfo *CMS_data_create(BIO *in, unsigned int flags)
+{
+    return CMS_data_create_ex(in, flags, NULL, NULL);
+}
+
 int CMS_digest_verify(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
                       unsigned int flags)
 {
     BIO *cont;
     int r;
+
     if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_digest) {
-        CMSerr(CMS_F_CMS_DIGEST_VERIFY, CMS_R_TYPE_NOT_DIGESTED_DATA);
+        ERR_raise(ERR_LIB_CMS, CMS_R_TYPE_NOT_DIGESTED_DATA);
         return 0;
     }
 
-    if (!dcont && !check_content(cms))
+    if (dcont == NULL && !check_content(cms))
         return 0;
 
     cont = CMS_dataInit(cms, dcont);
-    if (!cont)
+    if (cont == NULL)
         return 0;
+
     r = cms_copy_content(out, cont, flags);
     if (r)
-        r = cms_DigestedData_do_final(cms, cont, 1);
+        r = ossl_cms_DigestedData_do_final(cms, cont, 1);
     do_free_upto(cont, dcont);
     return r;
 }
 
-CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
-                                   unsigned int flags)
+CMS_ContentInfo *CMS_digest_create_ex(BIO *in, const EVP_MD *md,
+                                      unsigned int flags, OSSL_LIB_CTX *ctx,
+                                      const char *propq)
 {
     CMS_ContentInfo *cms;
-    if (!md)
+
+    /*
+     * Because the EVP_MD is cached and can be a legacy algorithm, we
+     * cannot fetch the algorithm if it isn't supplied.
+     */
+    if (md == NULL)
         md = EVP_sha1();
-    cms = cms_DigestedData_create(md);
-    if (!cms)
+    cms = ossl_cms_DigestedData_create(md, ctx, propq);
+    if (cms == NULL)
         return NULL;
 
     if (!(flags & CMS_DETACHED))
@@ -218,41 +189,50 @@ CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
     return NULL;
 }
 
+CMS_ContentInfo *CMS_digest_create(BIO *in, const EVP_MD *md,
+                                   unsigned int flags)
+{
+    return CMS_digest_create_ex(in, md, flags, NULL, NULL);
+}
+
 int CMS_EncryptedData_decrypt(CMS_ContentInfo *cms,
                               const unsigned char *key, size_t keylen,
                               BIO *dcont, BIO *out, unsigned int flags)
 {
     BIO *cont;
     int r;
+
     if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_encrypted) {
-        CMSerr(CMS_F_CMS_ENCRYPTEDDATA_DECRYPT,
-               CMS_R_TYPE_NOT_ENCRYPTED_DATA);
+        ERR_raise(ERR_LIB_CMS, CMS_R_TYPE_NOT_ENCRYPTED_DATA);
         return 0;
     }
 
-    if (!dcont && !check_content(cms))
+    if (dcont == NULL && !check_content(cms))
         return 0;
 
     if (CMS_EncryptedData_set1_key(cms, NULL, key, keylen) <= 0)
         return 0;
     cont = CMS_dataInit(cms, dcont);
-    if (!cont)
+    if (cont == NULL)
         return 0;
     r = cms_copy_content(out, cont, flags);
     do_free_upto(cont, dcont);
     return r;
 }
 
-CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
-                                           const unsigned char *key,
-                                           size_t keylen, unsigned int flags)
+CMS_ContentInfo *CMS_EncryptedData_encrypt_ex(BIO *in, const EVP_CIPHER *cipher,
+                                              const unsigned char *key,
+                                              size_t keylen, unsigned int flags,
+                                              OSSL_LIB_CTX *libctx,
+                                              const char *propq)
 {
     CMS_ContentInfo *cms;
-    if (!cipher) {
-        CMSerr(CMS_F_CMS_ENCRYPTEDDATA_ENCRYPT, CMS_R_NO_CIPHER);
+
+    if (cipher == NULL) {
+        ERR_raise(ERR_LIB_CMS, CMS_R_NO_CIPHER);
         return NULL;
     }
-    cms = CMS_ContentInfo_new();
+    cms = CMS_ContentInfo_new_ex(libctx, propq);
     if (cms == NULL)
         return NULL;
     if (!CMS_EncryptedData_set1_key(cms, cipher, key, keylen))
@@ -269,36 +249,54 @@ CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
     return NULL;
 }
 
+CMS_ContentInfo *CMS_EncryptedData_encrypt(BIO *in, const EVP_CIPHER *cipher,
+                                           const unsigned char *key,
+                                           size_t keylen, unsigned int flags)
+{
+    return CMS_EncryptedData_encrypt_ex(in, cipher, key, keylen, flags, NULL,
+                                        NULL);
+}
+
 static int cms_signerinfo_verify_cert(CMS_SignerInfo *si,
                                       X509_STORE *store,
                                       STACK_OF(X509) *certs,
                                       STACK_OF(X509_CRL) *crls,
-                                      unsigned int flags)
+                                      STACK_OF(X509) **chain,
+                                      const CMS_CTX *cms_ctx)
 {
-    X509_STORE_CTX ctx;
+    X509_STORE_CTX *ctx;
     X509 *signer;
     int i, j, r = 0;
+
+    ctx = X509_STORE_CTX_new_ex(ossl_cms_ctx_get0_libctx(cms_ctx),
+                                ossl_cms_ctx_get0_propq(cms_ctx));
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
     CMS_SignerInfo_get0_algs(si, NULL, &signer, NULL, NULL);
-    if (!X509_STORE_CTX_init(&ctx, store, signer, certs)) {
-        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT, CMS_R_STORE_INIT_ERROR);
+    if (!X509_STORE_CTX_init(ctx, store, signer, certs)) {
+        ERR_raise(ERR_LIB_CMS, CMS_R_STORE_INIT_ERROR);
         goto err;
     }
-    X509_STORE_CTX_set_default(&ctx, "smime_sign");
-    if (crls)
-        X509_STORE_CTX_set0_crls(&ctx, crls);
+    X509_STORE_CTX_set_default(ctx, "smime_sign");
+    if (crls != NULL)
+        X509_STORE_CTX_set0_crls(ctx, crls);
 
-    i = X509_verify_cert(&ctx);
+    i = X509_verify_cert(ctx);
     if (i <= 0) {
-        j = X509_STORE_CTX_get_error(&ctx);
-        CMSerr(CMS_F_CMS_SIGNERINFO_VERIFY_CERT,
-               CMS_R_CERTIFICATE_VERIFY_ERROR);
-        ERR_add_error_data(2, "Verify error:",
-                           X509_verify_cert_error_string(j));
+        j = X509_STORE_CTX_get_error(ctx);
+        ERR_raise_data(ERR_LIB_CMS, CMS_R_CERTIFICATE_VERIFY_ERROR,
+                       "Verify error: %s", X509_verify_cert_error_string(j));
         goto err;
     }
     r = 1;
+
+    /* also send back the trust chain when required */
+    if (chain != NULL)
+        *chain = X509_STORE_CTX_get1_chain(ctx);
  err:
-    X509_STORE_CTX_cleanup(&ctx);
+    X509_STORE_CTX_free(ctx);
     return r;
 
 }
@@ -310,14 +308,18 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
     STACK_OF(CMS_SignerInfo) *sinfos;
     STACK_OF(X509) *cms_certs = NULL;
     STACK_OF(X509_CRL) *crls = NULL;
+    STACK_OF(X509) **si_chains = NULL;
     X509 *signer;
     int i, scount = 0, ret = 0;
     BIO *cmsbio = NULL, *tmpin = NULL, *tmpout = NULL;
+    int cadesVerify = (flags & CMS_CADES) != 0;
+    const CMS_CTX *ctx = ossl_cms_get0_cmsctx(cms);
 
-    if (!dcont && !check_content(cms))
+    if (dcont == NULL && !check_content(cms))
         return 0;
-    if (dcont && !(flags & CMS_BINARY)) {
+    if (dcont != NULL && !(flags & CMS_BINARY)) {
         const ASN1_OBJECT *coid = CMS_get0_eContentType(cms);
+
         if (OBJ_obj2nid(coid) == NID_id_ct_asciiTextWithCRLF)
             flags |= CMS_ASCIICRLF;
     }
@@ -327,7 +329,7 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
     sinfos = CMS_get0_SignerInfos(cms);
 
     if (sk_CMS_SignerInfo_num(sinfos) <= 0) {
-        CMSerr(CMS_F_CMS_VERIFY, CMS_R_NO_SIGNERS);
+        ERR_raise(ERR_LIB_CMS, CMS_R_NO_SIGNERS);
         goto err;
     }
 
@@ -342,33 +344,50 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
         scount += CMS_set1_signers_certs(cms, certs, flags);
 
     if (scount != sk_CMS_SignerInfo_num(sinfos)) {
-        CMSerr(CMS_F_CMS_VERIFY, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND);
+        ERR_raise(ERR_LIB_CMS, CMS_R_SIGNER_CERTIFICATE_NOT_FOUND);
         goto err;
     }
 
     /* Attempt to verify all signers certs */
-
-    if (!(flags & CMS_NO_SIGNER_CERT_VERIFY)) {
+    /* at this point scount == sk_CMS_SignerInfo_num(sinfos) */
+
+    if ((flags & CMS_NO_SIGNER_CERT_VERIFY) == 0 || cadesVerify) {
+        if (cadesVerify) {
+            /* Certificate trust chain is required to check CAdES signature */
+            si_chains = OPENSSL_zalloc(scount * sizeof(si_chains[0]));
+            if (si_chains == NULL) {
+                ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+        }
         cms_certs = CMS_get1_certs(cms);
         if (!(flags & CMS_NOCRL))
             crls = CMS_get1_crls(cms);
-        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
+        for (i = 0; i < scount; i++) {
             si = sk_CMS_SignerInfo_value(sinfos, i);
-            if (!cms_signerinfo_verify_cert(si, store,
-                                            cms_certs, crls, flags))
+
+            if (!cms_signerinfo_verify_cert(si, store, cms_certs, crls,
+                                            si_chains ? &si_chains[i] : NULL,
+                                            ctx))
                 goto err;
         }
     }
 
     /* Attempt to verify all SignerInfo signed attribute signatures */
 
-    if (!(flags & CMS_NO_ATTR_VERIFY)) {
-        for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
+    if ((flags & CMS_NO_ATTR_VERIFY) == 0 || cadesVerify) {
+        for (i = 0; i < scount; i++) {
             si = sk_CMS_SignerInfo_value(sinfos, i);
             if (CMS_signed_get_attr_count(si) < 0)
                 continue;
             if (CMS_SignerInfo_verify(si) <= 0)
                 goto err;
+            if (cadesVerify) {
+                STACK_OF(X509) *si_chain = si_chains ? si_chains[i] : NULL;
+
+                if (ossl_cms_check_signing_certs(si, si_chain) <= 0)
+                    goto err;
+            }
         }
     }
 
@@ -379,17 +398,19 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
      * reading from a read write memory BIO when signatures are calculated.
      */
 
-    if (dcont && (BIO_method_type(dcont) == BIO_TYPE_MEM)) {
+    if (dcont != NULL && (BIO_method_type(dcont) == BIO_TYPE_MEM)) {
         char *ptr;
         long len;
+
         len = BIO_get_mem_data(dcont, &ptr);
-        tmpin = BIO_new_mem_buf(ptr, len);
+        tmpin = (len == 0) ? dcont : BIO_new_mem_buf(ptr, len);
         if (tmpin == NULL) {
-            CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE);
+            ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
             goto err2;
         }
-    } else
+    } else {
         tmpin = dcont;
+    }
     /*
      * If not binary mode and detached generate digests by *writing* through
      * the BIO. That makes it possible to canonicalise the input.
@@ -400,12 +421,12 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
          * included content doesn't override detached content.
          */
         tmpout = cms_get_text_bio(out, flags);
-        if (!tmpout) {
-            CMSerr(CMS_F_CMS_VERIFY, ERR_R_MALLOC_FAILURE);
+        if (tmpout == NULL) {
+            ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
             goto err;
         }
         cmsbio = CMS_dataInit(cms, tmpout);
-        if (!cmsbio)
+        if (cmsbio == NULL)
             goto err;
         /*
          * Don't use SMIME_TEXT for verify: it adds headers and we want to
@@ -415,13 +436,13 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
 
         if (flags & CMS_TEXT) {
             if (!SMIME_text(tmpout, out)) {
-                CMSerr(CMS_F_CMS_VERIFY, CMS_R_SMIME_TEXT_ERROR);
+                ERR_raise(ERR_LIB_CMS, CMS_R_SMIME_TEXT_ERROR);
                 goto err;
             }
         }
     } else {
         cmsbio = CMS_dataInit(cms, tmpin);
-        if (!cmsbio)
+        if (cmsbio == NULL)
             goto err;
 
         if (!cms_copy_content(out, cmsbio, flags))
@@ -432,14 +453,13 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
         for (i = 0; i < sk_CMS_SignerInfo_num(sinfos); i++) {
             si = sk_CMS_SignerInfo_value(sinfos, i);
             if (CMS_SignerInfo_verify_content(si, cmsbio) <= 0) {
-                CMSerr(CMS_F_CMS_VERIFY, CMS_R_CONTENT_VERIFY_ERROR);
+                ERR_raise(ERR_LIB_CMS, CMS_R_CONTENT_VERIFY_ERROR);
                 goto err;
             }
         }
     }
 
     ret = 1;
-
  err:
     if (!(flags & SMIME_BINARY) && dcont) {
         do_free_upto(cmsbio, tmpout);
@@ -456,7 +476,12 @@ int CMS_verify(CMS_ContentInfo *cms, STACK_OF(X509) *certs,
         BIO_free_all(tmpout);
 
  err2:
-    sk_X509_pop_free(cms_certs, X509_free);
+    if (si_chains != NULL) {
+        for (i = 0; i < scount; ++i)
+            OSSL_STACK_OF_X509_free(si_chains[i]);
+        OPENSSL_free(si_chains);
+    }
+    OSSL_STACK_OF_X509_free(cms_certs);
     sk_X509_CRL_pop_free(crls, X509_CRL_free);
 
     return ret;
@@ -467,21 +492,23 @@ int CMS_verify_receipt(CMS_ContentInfo *rcms, CMS_ContentInfo *ocms,
                        X509_STORE *store, unsigned int flags)
 {
     int r;
+
     flags &= ~(CMS_DETACHED | CMS_TEXT);
     r = CMS_verify(rcms, certs, store, NULL, NULL, flags);
     if (r <= 0)
         return r;
-    return cms_Receipt_verify(rcms, ocms);
+    return ossl_cms_Receipt_verify(rcms, ocms);
 }
 
-CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey,
-                          STACK_OF(X509) *certs, BIO *data,
-                          unsigned int flags)
+CMS_ContentInfo *CMS_sign_ex(X509 *signcert, EVP_PKEY *pkey,
+                             STACK_OF(X509) *certs, BIO *data,
+                             unsigned int flags, OSSL_LIB_CTX *libctx,
+                             const char *propq)
 {
     CMS_ContentInfo *cms;
     int i;
 
-    cms = CMS_ContentInfo_new();
+    cms = CMS_ContentInfo_new_ex(libctx, propq);
     if (cms == NULL || !CMS_SignedData_init(cms))
         goto merr;
     if (flags & CMS_ASCIICRLF
@@ -489,13 +516,14 @@ CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey,
                                   OBJ_nid2obj(NID_id_ct_asciiTextWithCRLF)))
         goto err;
 
-    if (pkey && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) {
-        CMSerr(CMS_F_CMS_SIGN, CMS_R_ADD_SIGNER_ERROR);
+    if (pkey != NULL && !CMS_add1_signer(cms, signcert, pkey, NULL, flags)) {
+        ERR_raise(ERR_LIB_CMS, CMS_R_ADD_SIGNER_ERROR);
         goto err;
     }
 
     for (i = 0; i < sk_X509_num(certs); i++) {
         X509 *x = sk_X509_value(certs, i);
+
         if (!CMS_add1_cert(cms, x))
             goto merr;
     }
@@ -510,13 +538,19 @@ CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey,
         goto err;
 
  merr:
-    CMSerr(CMS_F_CMS_SIGN, ERR_R_MALLOC_FAILURE);
+    ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
 
  err:
     CMS_ContentInfo_free(cms);
     return NULL;
 }
 
+CMS_ContentInfo *CMS_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
+                          BIO *data, unsigned int flags)
+{
+    return CMS_sign_ex(signcert, pkey, certs, data, flags, NULL, NULL);
+}
+
 CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
                                   X509 *signcert, EVP_PKEY *pkey,
                                   STACK_OF(X509) *certs, unsigned int flags)
@@ -526,19 +560,22 @@ CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
     ASN1_OCTET_STRING **pos, *os;
     BIO *rct_cont = NULL;
     int r = 0;
+    const CMS_CTX *ctx = si->cms_ctx;
 
     flags &= ~(CMS_STREAM | CMS_TEXT);
     /* Not really detached but avoids content being allocated */
     flags |= CMS_PARTIAL | CMS_BINARY | CMS_DETACHED;
-    if (!pkey || !signcert) {
-        CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_NO_KEY_OR_CERT);
+    if (pkey == NULL || signcert == NULL) {
+        ERR_raise(ERR_LIB_CMS, CMS_R_NO_KEY_OR_CERT);
         return NULL;
     }
 
     /* Initialize signed data */
 
-    cms = CMS_sign(NULL, NULL, certs, NULL, flags);
-    if (!cms)
+    cms = CMS_sign_ex(NULL, NULL, certs, NULL, flags,
+                      ossl_cms_ctx_get0_libctx(ctx),
+                      ossl_cms_ctx_get0_propq(ctx));
+    if (cms == NULL)
         goto err;
 
     /* Set inner content type to signed receipt */
@@ -547,23 +584,22 @@ CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
 
     rct_si = CMS_add1_signer(cms, signcert, pkey, NULL, flags);
     if (!rct_si) {
-        CMSerr(CMS_F_CMS_SIGN_RECEIPT, CMS_R_ADD_SIGNER_ERROR);
+        ERR_raise(ERR_LIB_CMS, CMS_R_ADD_SIGNER_ERROR);
         goto err;
     }
 
-    os = cms_encode_Receipt(si);
-
-    if (!os)
+    os = ossl_cms_encode_Receipt(si);
+    if (os == NULL)
         goto err;
 
     /* Set content to digest */
     rct_cont = BIO_new_mem_buf(os->data, os->length);
-    if (!rct_cont)
+    if (rct_cont == NULL)
         goto err;
 
     /* Add msgSigDigest attribute */
 
-    if (!cms_msgSigDigest_add1(rct_si, si))
+    if (!ossl_cms_msgSigDigest_add1(rct_si, si))
         goto err;
 
     /* Finalize structure */
@@ -572,6 +608,8 @@ CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
 
     /* Set embedded content */
     pos = CMS_get0_content(cms);
+    if (pos == NULL)
+        goto err;
     *pos = os;
 
     r = 1;
@@ -585,19 +623,24 @@ CMS_ContentInfo *CMS_sign_receipt(CMS_SignerInfo *si,
 
 }
 
-CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
-                             const EVP_CIPHER *cipher, unsigned int flags)
+CMS_ContentInfo *CMS_encrypt_ex(STACK_OF(X509) *certs, BIO *data,
+                                const EVP_CIPHER *cipher, unsigned int flags,
+                                OSSL_LIB_CTX *libctx, const char *propq)
 {
     CMS_ContentInfo *cms;
     int i;
     X509 *recip;
-    cms = CMS_EnvelopedData_create(cipher);
-    if (!cms)
+
+
+    cms = (EVP_CIPHER_get_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)
+          ? CMS_AuthEnvelopedData_create_ex(cipher, libctx, propq)
+          : CMS_EnvelopedData_create_ex(cipher, libctx, propq);
+    if (cms == NULL)
         goto merr;
     for (i = 0; i < sk_X509_num(certs); i++) {
         recip = sk_X509_value(certs, i);
         if (!CMS_add1_recipient_cert(cms, recip, flags)) {
-            CMSerr(CMS_F_CMS_ENCRYPT, CMS_R_RECIPIENT_ERROR);
+            ERR_raise(ERR_LIB_CMS, CMS_R_RECIPIENT_ERROR);
             goto err;
         }
     }
@@ -612,59 +655,76 @@ CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
         goto err;
 
  merr:
-    CMSerr(CMS_F_CMS_ENCRYPT, ERR_R_MALLOC_FAILURE);
+    ERR_raise(ERR_LIB_CMS, ERR_R_MALLOC_FAILURE);
  err:
     CMS_ContentInfo_free(cms);
     return NULL;
 }
 
-static int cms_kari_set1_pkey(CMS_ContentInfo *cms, CMS_RecipientInfo *ri,
-                              EVP_PKEY *pk, X509 *cert)
+CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *data,
+                             const EVP_CIPHER *cipher, unsigned int flags)
+{
+    return CMS_encrypt_ex(certs, data, cipher, flags, NULL, NULL);
+}
+
+static int cms_kari_set1_pkey_and_peer(CMS_ContentInfo *cms,
+                                       CMS_RecipientInfo *ri,
+                                       EVP_PKEY *pk, X509 *cert, X509 *peer)
 {
     int i;
     STACK_OF(CMS_RecipientEncryptedKey) *reks;
     CMS_RecipientEncryptedKey *rek;
+
     reks = CMS_RecipientInfo_kari_get0_reks(ri);
-    if (!cert)
-        return 0;
     for (i = 0; i < sk_CMS_RecipientEncryptedKey_num(reks); i++) {
         int rv;
+
         rek = sk_CMS_RecipientEncryptedKey_value(reks, i);
-        if (CMS_RecipientEncryptedKey_cert_cmp(rek, cert))
+        if (cert != NULL && CMS_RecipientEncryptedKey_cert_cmp(rek, cert))
             continue;
-        CMS_RecipientInfo_kari_set0_pkey(ri, pk);
+        CMS_RecipientInfo_kari_set0_pkey_and_peer(ri, pk, peer);
         rv = CMS_RecipientInfo_kari_decrypt(cms, ri, rek);
         CMS_RecipientInfo_kari_set0_pkey(ri, NULL);
         if (rv > 0)
             return 1;
-        return -1;
+        return cert == NULL ? 0 : -1;
     }
     return 0;
 }
 
 int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
+{
+     return CMS_decrypt_set1_pkey_and_peer(cms, pk, cert, NULL);
+}
+
+int CMS_decrypt_set1_pkey_and_peer(CMS_ContentInfo *cms, EVP_PKEY *pk,
+                                   X509 *cert, X509 *peer)
 {
     STACK_OF(CMS_RecipientInfo) *ris;
     CMS_RecipientInfo *ri;
-    int i, r, ri_type;
+    int i, r, cms_pkey_ri_type;
     int debug = 0, match_ri = 0;
+
     ris = CMS_get0_RecipientInfos(cms);
-    if (ris)
-        debug = cms->d.envelopedData->encryptedContentInfo->debug;
-    ri_type = cms_pkey_get_ri_type(pk);
-    if (ri_type == CMS_RECIPINFO_NONE) {
-        CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY,
-               CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
-        return 0;
+    if (ris != NULL)
+        debug = ossl_cms_get0_env_enc_content(cms)->debug;
+
+    cms_pkey_ri_type = ossl_cms_pkey_get_ri_type(pk);
+    if (cms_pkey_ri_type == CMS_RECIPINFO_NONE) {
+         ERR_raise(ERR_LIB_CMS, CMS_R_NOT_SUPPORTED_FOR_THIS_KEY_TYPE);
+         return 0;
     }
 
     for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
+        int ri_type;
+
         ri = sk_CMS_RecipientInfo_value(ris, i);
-        if (CMS_RecipientInfo_type(ri) != ri_type)
+        ri_type = CMS_RecipientInfo_type(ri);
+        if (!ossl_cms_pkey_is_ri_type_supported(pk, ri_type))
             continue;
         match_ri = 1;
         if (ri_type == CMS_RECIPINFO_AGREE) {
-            r = cms_kari_set1_pkey(cms, ri, pk, cert);
+            r = cms_kari_set1_pkey_and_peer(cms, ri, pk, cert, peer);
             if (r > 0)
                 return 1;
             if (r < 0)
@@ -674,11 +734,12 @@ int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
          * If we have a cert try matching RecipientInfo otherwise try them
          * all.
          */
-        else if (!cert || !CMS_RecipientInfo_ktri_cert_cmp(ri, cert)) {
+        else if (cert == NULL|| !CMS_RecipientInfo_ktri_cert_cmp(ri, cert)) {
+            EVP_PKEY_up_ref(pk);
             CMS_RecipientInfo_set0_pkey(ri, pk);
             r = CMS_RecipientInfo_decrypt(cms, ri);
             CMS_RecipientInfo_set0_pkey(ri, NULL);
-            if (cert) {
+            if (cert != NULL) {
                 /*
                  * If not debugging clear any error and return success to
                  * avoid leaking of information useful to MMA
@@ -689,7 +750,7 @@ int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
                 }
                 if (r > 0)
                     return 1;
-                CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_DECRYPT_ERROR);
+                ERR_raise(ERR_LIB_CMS, CMS_R_DECRYPT_ERROR);
                 return 0;
             }
             /*
@@ -697,28 +758,32 @@ int CMS_decrypt_set1_pkey(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert)
              * successful decrypt. Always attempt to decrypt all recipients
              * to avoid leaking timing of a successful decrypt.
              */
-            else if (r > 0 && debug)
+            else if (r > 0 && (debug || cms_pkey_ri_type != CMS_RECIPINFO_TRANS))
                 return 1;
         }
     }
-    /* If no cert and not debugging always return success */
-    if (match_ri && !cert && !debug) {
+    /* If no cert, key transport and not debugging always return success */
+    if (cert == NULL
+        && cms_pkey_ri_type == CMS_RECIPINFO_TRANS
+        && match_ri
+        && !debug) {
         ERR_clear_error();
         return 1;
     }
 
-    CMSerr(CMS_F_CMS_DECRYPT_SET1_PKEY, CMS_R_NO_MATCHING_RECIPIENT);
+    ERR_raise(ERR_LIB_CMS, CMS_R_NO_MATCHING_RECIPIENT);
     return 0;
 
 }
 
 int CMS_decrypt_set1_key(CMS_ContentInfo *cms,
                          unsigned char *key, size_t keylen,
-                         unsigned char *id, size_t idlen)
+                         const unsigned char *id, size_t idlen)
 {
     STACK_OF(CMS_RecipientInfo) *ris;
     CMS_RecipientInfo *ri;
     int i, r;
+
     ris = CMS_get0_RecipientInfos(cms);
     for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
         ri = sk_CMS_RecipientInfo_value(ris, i);
@@ -729,21 +794,21 @@ int CMS_decrypt_set1_key(CMS_ContentInfo *cms,
          * If we have an id try matching RecipientInfo otherwise try them
          * all.
          */
-        if (!id || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) {
+        if (id == NULL || (CMS_RecipientInfo_kekri_id_cmp(ri, id, idlen) == 0)) {
             CMS_RecipientInfo_set0_key(ri, key, keylen);
             r = CMS_RecipientInfo_decrypt(cms, ri);
             CMS_RecipientInfo_set0_key(ri, NULL, 0);
             if (r > 0)
                 return 1;
-            if (id) {
-                CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_DECRYPT_ERROR);
+            if (id != NULL) {
+                ERR_raise(ERR_LIB_CMS, CMS_R_DECRYPT_ERROR);
                 return 0;
             }
             ERR_clear_error();
         }
     }
 
-    CMSerr(CMS_F_CMS_DECRYPT_SET1_KEY, CMS_R_NO_MATCHING_RECIPIENT);
+    ERR_raise(ERR_LIB_CMS, CMS_R_NO_MATCHING_RECIPIENT);
     return 0;
 
 }
@@ -754,6 +819,7 @@ int CMS_decrypt_set1_password(CMS_ContentInfo *cms,
     STACK_OF(CMS_RecipientInfo) *ris;
     CMS_RecipientInfo *ri;
     int i, r;
+
     ris = CMS_get0_RecipientInfos(cms);
     for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
         ri = sk_CMS_RecipientInfo_value(ris, i);
@@ -766,7 +832,7 @@ int CMS_decrypt_set1_password(CMS_ContentInfo *cms,
             return 1;
     }
 
-    CMSerr(CMS_F_CMS_DECRYPT_SET1_PASSWORD, CMS_R_NO_MATCHING_RECIPIENT);
+    ERR_raise(ERR_LIB_CMS, CMS_R_NO_MATCHING_RECIPIENT);
     return 0;
 
 }
@@ -776,22 +842,30 @@ int CMS_decrypt(CMS_ContentInfo *cms, EVP_PKEY *pk, X509 *cert,
 {
     int r;
     BIO *cont;
-    if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_pkcs7_enveloped) {
-        CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA);
+
+    int nid = OBJ_obj2nid(CMS_get0_type(cms));
+
+    if (nid != NID_pkcs7_enveloped
+            && nid != NID_id_smime_ct_authEnvelopedData) {
+        ERR_raise(ERR_LIB_CMS, CMS_R_TYPE_NOT_ENVELOPED_DATA);
         return 0;
     }
-    if (!dcont && !check_content(cms))
+    if (dcont == NULL && !check_content(cms))
         return 0;
     if (flags & CMS_DEBUG_DECRYPT)
-        cms->d.envelopedData->encryptedContentInfo->debug = 1;
+        ossl_cms_get0_env_enc_content(cms)->debug = 1;
+    else
+        ossl_cms_get0_env_enc_content(cms)->debug = 0;
+    if (cert == NULL)
+        ossl_cms_get0_env_enc_content(cms)->havenocert = 1;
     else
-        cms->d.envelopedData->encryptedContentInfo->debug = 0;
-    if (!pk && !cert && !dcont && !out)
+        ossl_cms_get0_env_enc_content(cms)->havenocert = 0;
+    if (pk == NULL && cert == NULL && dcont == NULL && out == NULL)
         return 1;
-    if (pk && !CMS_decrypt_set1_pkey(cms, pk, cert))
+    if (pk != NULL && !CMS_decrypt_set1_pkey(cms, pk, cert))
         return 0;
     cont = CMS_dataInit(cms, dcont);
-    if (!cont)
+    if (cont == NULL)
         return 0;
     r = cms_copy_content(out, cont, flags);
     do_free_upto(cont, dcont);
@@ -804,22 +878,19 @@ int CMS_final(CMS_ContentInfo *cms, BIO *data, BIO *dcont, unsigned int flags)
     int ret = 0;
 
     if ((cmsbio = CMS_dataInit(cms, dcont)) == NULL) {
-        CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_LIB);
+        ERR_raise(ERR_LIB_CMS, CMS_R_CMS_LIB);
         return 0;
     }
 
-    SMIME_crlf_copy(data, cmsbio, flags);
+    ret = SMIME_crlf_copy(data, cmsbio, flags);
 
     (void)BIO_flush(cmsbio);
 
     if (!CMS_dataFinal(cms, cmsbio)) {
-        CMSerr(CMS_F_CMS_FINAL, CMS_R_CMS_DATAFINAL_ERROR);
+        ERR_raise(ERR_LIB_CMS, CMS_R_CMS_DATAFINAL_ERROR);
         goto err;
     }
-
-    ret = 1;
-
- err:
+err:
     do_free_upto(cmsbio, dcont);
 
     return ret;
@@ -833,16 +904,17 @@ int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
 {
     BIO *cont;
     int r;
+
     if (OBJ_obj2nid(CMS_get0_type(cms)) != NID_id_smime_ct_compressedData) {
-        CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_TYPE_NOT_COMPRESSED_DATA);
+        ERR_raise(ERR_LIB_CMS, CMS_R_TYPE_NOT_COMPRESSED_DATA);
         return 0;
     }
 
-    if (!dcont && !check_content(cms))
+    if (dcont == NULL && !check_content(cms))
         return 0;
 
     cont = CMS_dataInit(cms, dcont);
-    if (!cont)
+    if (cont == NULL)
         return 0;
     r = cms_copy_content(out, cont, flags);
     do_free_upto(cont, dcont);
@@ -852,10 +924,11 @@ int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
 CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
 {
     CMS_ContentInfo *cms;
+
     if (comp_nid <= 0)
         comp_nid = NID_zlib_compression;
-    cms = cms_CompressedData_create(comp_nid);
-    if (!cms)
+    cms = ossl_cms_CompressedData_create(comp_nid, NULL, NULL);
+    if (cms == NULL)
         return NULL;
 
     if (!(flags & CMS_DETACHED))
@@ -873,13 +946,13 @@ CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
 int CMS_uncompress(CMS_ContentInfo *cms, BIO *dcont, BIO *out,
                    unsigned int flags)
 {
-    CMSerr(CMS_F_CMS_UNCOMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+    ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
     return 0;
 }
 
 CMS_ContentInfo *CMS_compress(BIO *in, int comp_nid, unsigned int flags)
 {
-    CMSerr(CMS_F_CMS_COMPRESS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
+    ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
     return NULL;
 }