[openssl] master update

tmraz at fedoraproject.org tmraz at fedoraproject.org
Tue Sep 8 13:43:44 UTC 2020


The branch master has been updated
       via  924663c36d47066d5307937da77fed7e872730c7 (commit)
      from  d96486dc809b5d134055785bfa6d707195d95534 (commit)


- Log -----------------------------------------------------------------
commit 924663c36d47066d5307937da77fed7e872730c7
Author: Jakub Zelenka <jakub.openssl at gmail.com>
Date:   Sun Sep 6 19:11:34 2020 +0100

    Add CMS AuthEnvelopedData with AES-GCM support
    
    Add the AuthEnvelopedData as defined in RFC 5083 with AES-GCM
    parameter as defined in RFC 5084.
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    Reviewed-by: Tomas Mraz <tmraz at fedoraproject.org>
    (Merged from https://github.com/openssl/openssl/pull/8024)

-----------------------------------------------------------------------

Summary of changes:
 crypto/asn1/evp_asn1.c                | 108 +++++++++--
 crypto/cms/cms_asn1.c                 |  12 ++
 crypto/cms/cms_enc.c                  |  32 +++-
 crypto/cms/cms_env.c                  | 345 ++++++++++++++++++++++++++--------
 crypto/cms/cms_err.c                  |   3 +
 crypto/cms/cms_kari.c                 |   4 +-
 crypto/cms/cms_lib.c                  |  24 +++
 crypto/cms/cms_local.h                |  21 ++-
 crypto/cms/cms_pwri.c                 |  16 +-
 crypto/cms/cms_smime.c                |  20 +-
 crypto/err/openssl.txt                |   3 +
 crypto/evp/evp_lib.c                  | 107 ++++++++---
 crypto/evp/evp_local.h                |   5 +
 doc/man1/openssl-cms.pod.in           |   3 +
 doc/man3/CMS_EnvelopedData_create.pod |  48 +++--
 doc/man3/CMS_decrypt.pod              |   6 +-
 doc/man3/CMS_encrypt.pod              |  22 ++-
 include/crypto/asn1.h                 |   9 +
 include/crypto/evp.h                  |  12 ++
 include/openssl/asn1err.h             |   1 +
 include/openssl/cms.h                 |   5 +
 include/openssl/cmserr.h              |   2 +
 test/cmsapitest.c                     |  29 ++-
 test/drbgtest.c                       |   1 +
 test/recipes/80-test_cms.t            |  26 ++-
 util/libcrypto.num                    |   2 +
 26 files changed, 686 insertions(+), 180 deletions(-)

diff --git a/crypto/asn1/evp_asn1.c b/crypto/asn1/evp_asn1.c
index c775a22181..844aabe603 100644
--- a/crypto/asn1/evp_asn1.c
+++ b/crypto/asn1/evp_asn1.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-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
@@ -11,6 +11,7 @@
 #include "internal/cryptlib.h"
 #include <openssl/asn1.h>
 #include <openssl/asn1t.h>
+#include "crypto/asn1.h"
 
 int ASN1_TYPE_set_octetstring(ASN1_TYPE *a, unsigned char *data, int len)
 {
@@ -46,6 +47,34 @@ int ASN1_TYPE_get_octetstring(const ASN1_TYPE *a, unsigned char *data, int max_l
     return ret;
 }
 
+static ossl_inline void asn1_type_init_oct(ASN1_OCTET_STRING *oct,
+                                           unsigned char *data, int len)
+{
+    oct->data = data;
+    oct->type = V_ASN1_OCTET_STRING;
+    oct->length = len;
+    oct->flags = 0;
+}
+
+static int asn1_type_get_int_oct(ASN1_OCTET_STRING *oct, int32_t anum,
+                                 long *num, unsigned char *data, int max_len)
+{
+    int ret = ASN1_STRING_length(oct), n;
+
+    if (num != NULL)
+        *num = anum;
+
+    if (max_len > ret)
+        n = ret;
+    else
+        n = max_len;
+
+    if (data != NULL)
+        memcpy(data, ASN1_STRING_get0_data(oct), n);
+
+    return ret;
+}
+
 typedef struct {
     int32_t num;
     ASN1_OCTET_STRING *oct;
@@ -66,25 +95,18 @@ int ASN1_TYPE_set_int_octetstring(ASN1_TYPE *a, long num, unsigned char *data,
 
     atmp.num = num;
     atmp.oct = &oct;
-    oct.data = data;
-    oct.type = V_ASN1_OCTET_STRING;
-    oct.length = len;
-    oct.flags = 0;
+    asn1_type_init_oct(&oct, data, len);
 
     if (ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(asn1_int_oct), &atmp, &a))
         return 1;
     return 0;
 }
 
-/*
- * we return the actual length...
- */
-/* int max_len:  for returned value    */
 int ASN1_TYPE_get_int_octetstring(const ASN1_TYPE *a, long *num,
                                   unsigned char *data, int max_len)
 {
     asn1_int_oct *atmp = NULL;
-    int ret = -1, n;
+    int ret = -1;
 
     if ((a->type != V_ASN1_SEQUENCE) || (a->value.sequence == NULL)) {
         goto err;
@@ -95,17 +117,8 @@ int ASN1_TYPE_get_int_octetstring(const ASN1_TYPE *a, long *num,
     if (atmp == NULL)
         goto err;
 
-    if (num != NULL)
-        *num = atmp->num;
+    ret = asn1_type_get_int_oct(atmp->oct, atmp->num, num, data, max_len);
 
-    ret = ASN1_STRING_length(atmp->oct);
-    if (max_len > ret)
-        n = ret;
-    else
-        n = max_len;
-
-    if (data != NULL)
-        memcpy(data, ASN1_STRING_get0_data(atmp->oct), n);
     if (ret == -1) {
  err:
         ASN1err(ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING, ASN1_R_DATA_IS_WRONG);
@@ -113,3 +126,58 @@ int ASN1_TYPE_get_int_octetstring(const ASN1_TYPE *a, long *num,
     M_ASN1_free_of(atmp, asn1_int_oct);
     return ret;
 }
+
+typedef struct {
+    ASN1_OCTET_STRING *oct;
+    int32_t num;
+} asn1_oct_int;
+
+/*
+ * Defined in RFC 5084 -
+ * Section 2. "Content-Authenticated Encryption Algorithms"
+ */
+ASN1_SEQUENCE(asn1_oct_int) = {
+        ASN1_SIMPLE(asn1_oct_int, oct, ASN1_OCTET_STRING),
+        ASN1_EMBED(asn1_oct_int, num, INT32)
+} static_ASN1_SEQUENCE_END(asn1_oct_int)
+
+DECLARE_ASN1_ITEM(asn1_oct_int)
+
+int asn1_type_set_octetstring_int(ASN1_TYPE *a, long num, unsigned char *data,
+                                  int len)
+{
+    asn1_oct_int atmp;
+    ASN1_OCTET_STRING oct;
+
+    atmp.num = num;
+    atmp.oct = &oct;
+    asn1_type_init_oct(&oct, data, len);
+
+    if (ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(asn1_oct_int), &atmp, &a))
+        return 1;
+    return 0;
+}
+
+int asn1_type_get_octetstring_int(const ASN1_TYPE *a, long *num,
+                                  unsigned char *data, int max_len)
+{
+    asn1_oct_int *atmp = NULL;
+    int ret = -1;
+
+    if ((a->type != V_ASN1_SEQUENCE) || (a->value.sequence == NULL))
+        goto err;
+
+    atmp = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(asn1_oct_int), a);
+
+    if (atmp == NULL)
+        goto err;
+
+    ret = asn1_type_get_int_oct(atmp->oct, atmp->num, num, data, max_len);
+
+    if (ret == -1) {
+ err:
+        ASN1err(ASN1_F_ASN1_TYPE_GET_OCTETSTRING_INT, ASN1_R_DATA_IS_WRONG);
+    }
+    M_ASN1_free_of(atmp, asn1_oct_int);
+    return ret;
+}
diff --git a/crypto/cms/cms_asn1.c b/crypto/cms/cms_asn1.c
index 082885dca8..8bf2f8f1cc 100644
--- a/crypto/cms/cms_asn1.c
+++ b/crypto/cms/cms_asn1.c
@@ -245,6 +245,17 @@ ASN1_NDEF_SEQUENCE(CMS_EncryptedData) = {
         ASN1_IMP_SET_OF_OPT(CMS_EncryptedData, unprotectedAttrs, X509_ATTRIBUTE, 1)
 } ASN1_NDEF_SEQUENCE_END(CMS_EncryptedData)
 
+/* Defined in RFC 5083 - Section 2.1. AuthEnvelopedData Type */
+ASN1_NDEF_SEQUENCE(CMS_AuthEnvelopedData) = {
+        ASN1_EMBED(CMS_AuthEnvelopedData, version, INT32),
+        ASN1_IMP_OPT(CMS_AuthEnvelopedData, originatorInfo, CMS_OriginatorInfo, 0),
+        ASN1_SET_OF(CMS_AuthEnvelopedData, recipientInfos, CMS_RecipientInfo),
+        ASN1_SIMPLE(CMS_AuthEnvelopedData, authEncryptedContentInfo, CMS_EncryptedContentInfo),
+        ASN1_IMP_SET_OF_OPT(CMS_AuthEnvelopedData, authAttrs, X509_ALGOR, 2),
+        ASN1_SIMPLE(CMS_AuthEnvelopedData, mac, ASN1_OCTET_STRING),
+        ASN1_IMP_SET_OF_OPT(CMS_AuthEnvelopedData, unauthAttrs, X509_ALGOR, 3)
+} ASN1_NDEF_SEQUENCE_END(CMS_AuthEnvelopedData)
+
 ASN1_NDEF_SEQUENCE(CMS_AuthenticatedData) = {
         ASN1_EMBED(CMS_AuthenticatedData, version, INT32),
         ASN1_IMP_OPT(CMS_AuthenticatedData, originatorInfo, CMS_OriginatorInfo, 0),
@@ -273,6 +284,7 @@ ASN1_ADB(CMS_ContentInfo) = {
         ADB_ENTRY(NID_pkcs7_enveloped, ASN1_NDEF_EXP(CMS_ContentInfo, d.envelopedData, CMS_EnvelopedData, 0)),
         ADB_ENTRY(NID_pkcs7_digest, ASN1_NDEF_EXP(CMS_ContentInfo, d.digestedData, CMS_DigestedData, 0)),
         ADB_ENTRY(NID_pkcs7_encrypted, ASN1_NDEF_EXP(CMS_ContentInfo, d.encryptedData, CMS_EncryptedData, 0)),
+        ADB_ENTRY(NID_id_smime_ct_authEnvelopedData, ASN1_NDEF_EXP(CMS_ContentInfo, d.authEnvelopedData, CMS_AuthEnvelopedData, 0)),
         ADB_ENTRY(NID_id_smime_ct_authData, ASN1_NDEF_EXP(CMS_ContentInfo, d.authenticatedData, CMS_AuthenticatedData, 0)),
         ADB_ENTRY(NID_id_smime_ct_compressedData, ASN1_NDEF_EXP(CMS_ContentInfo, d.compressedData, CMS_CompressedData, 0)),
 } ASN1_ADB_END(CMS_ContentInfo, 0, contentType, 0, &cms_default_tt, NULL);
diff --git a/crypto/cms/cms_enc.c b/crypto/cms/cms_enc.c
index 48934ef2a1..ef87fac8ef 100644
--- a/crypto/cms/cms_enc.c
+++ b/crypto/cms/cms_enc.c
@@ -14,6 +14,7 @@
 #include <openssl/err.h>
 #include <openssl/cms.h>
 #include <openssl/rand.h>
+#include "crypto/evp.h"
 #include "cms_local.h"
 
 /* CMS EncryptedData Utilities */
@@ -28,9 +29,11 @@ BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec,
     EVP_CIPHER *fetched_ciph = NULL;
     const EVP_CIPHER *cipher = NULL;
     X509_ALGOR *calg = ec->contentEncryptionAlgorithm;
+    evp_cipher_aead_asn1_params aparams;
     unsigned char iv[EVP_MAX_IV_LENGTH], *piv = NULL;
     unsigned char *tkey = NULL;
     int len;
+    int ivlen = 0;
     size_t tkeylen = 0;
     int ok = 0;
     int enc, keep_key = 0;
@@ -76,7 +79,6 @@ BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec,
     }
 
     if (enc) {
-        int ivlen;
         calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_type(ctx));
         /* Generate a random IV if we need one */
         ivlen = EVP_CIPHER_CTX_iv_length(ctx);
@@ -85,10 +87,20 @@ BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec,
                 goto err;
             piv = iv;
         }
-    } else if (EVP_CIPHER_asn1_to_param(ctx, calg->parameter) <= 0) {
-        CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
-               CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
-        goto err;
+    } else {
+        if (evp_cipher_asn1_to_param_ex(ctx, calg->parameter, &aparams) <= 0) {
+            CMSerr(0, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
+            goto err;
+        }
+        if ((EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)) {
+            piv = aparams.iv;
+            if (ec->taglen > 0
+                    && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
+                                           ec->taglen, ec->tag) <= 0) {
+                CMSerr(0, CMS_R_CIPHER_AEAD_SET_TAG_ERROR);
+                goto err;
+            }
+        }
     }
     len = EVP_CIPHER_CTX_key_length(ctx);
     if (len <= 0)
@@ -150,7 +162,15 @@ BIO *cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec,
             CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO, ERR_R_MALLOC_FAILURE);
             goto err;
         }
-        if (EVP_CIPHER_param_to_asn1(ctx, calg->parameter) <= 0) {
+        if ((EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)) {
+            memcpy(aparams.iv, piv, ivlen);
+            aparams.iv_len = ivlen;
+            aparams.tag_len = EVP_CIPHER_CTX_tag_length(ctx);
+            if (aparams.tag_len <= 0)
+                goto err;
+        }
+
+        if (evp_cipher_param_to_asn1_ex(ctx, calg->parameter, &aparams) <= 0) {
             CMSerr(CMS_F_CMS_ENCRYPTEDCONTENT_INIT_BIO,
                    CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR);
             goto err;
diff --git a/crypto/cms/cms_env.c b/crypto/cms/cms_env.c
index 1fed65c442..944846ca98 100644
--- a/crypto/cms/cms_env.c
+++ b/crypto/cms/cms_env.c
@@ -24,9 +24,28 @@ DEFINE_STACK_OF(CMS_RevocationInfoChoice)
 DEFINE_STACK_OF(X509_ATTRIBUTE)
 
 /* CMS EnvelopedData Utilities */
-
 static void cms_env_set_version(CMS_EnvelopedData *env);
 
+#define CMS_ENVELOPED_STANDARD 1
+#define CMS_ENVELOPED_AUTH     2
+
+static int cms_get_enveloped_type(const CMS_ContentInfo *cms)
+{
+    int nid = OBJ_obj2nid(cms->contentType);
+
+    switch (nid) {
+    case NID_pkcs7_enveloped:
+        return CMS_ENVELOPED_STANDARD;
+
+    case NID_id_smime_ct_authEnvelopedData:
+        return CMS_ENVELOPED_AUTH;
+
+    default:
+        CMSerr(0, CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA);
+        return 0;
+    }
+}
+
 CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms)
 {
     if (OBJ_obj2nid(cms->contentType) != NID_pkcs7_enveloped) {
@@ -37,11 +56,20 @@ CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms)
     return cms->d.envelopedData;
 }
 
+CMS_AuthEnvelopedData *cms_get0_auth_enveloped(CMS_ContentInfo *cms)
+{
+    if (OBJ_obj2nid(cms->contentType) != NID_id_smime_ct_authEnvelopedData) {
+        CMSerr(0, CMS_R_CONTENT_TYPE_NOT_ENVELOPED_DATA);
+        return NULL;
+    }
+    return cms->d.authEnvelopedData;
+}
+
 static CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms)
 {
     if (cms->d.other == NULL) {
         cms->d.envelopedData = M_ASN1_new_of(CMS_EnvelopedData);
-        if (!cms->d.envelopedData) {
+        if (cms->d.envelopedData == NULL) {
             CMSerr(CMS_F_CMS_ENVELOPED_DATA_INIT, ERR_R_MALLOC_FAILURE);
             return NULL;
         }
@@ -55,6 +83,26 @@ static CMS_EnvelopedData *cms_enveloped_data_init(CMS_ContentInfo *cms)
     return cms_get0_enveloped(cms);
 }
 
+static CMS_AuthEnvelopedData *
+cms_auth_enveloped_data_init(CMS_ContentInfo *cms)
+{
+    if (cms->d.other == NULL) {
+        cms->d.authEnvelopedData = M_ASN1_new_of(CMS_AuthEnvelopedData);
+        if (cms->d.authEnvelopedData == NULL) {
+            CMSerr(0, ERR_R_MALLOC_FAILURE);
+            return NULL;
+        }
+        /* Defined in RFC 5083 - Section 2.1. "AuthEnvelopedData Type" */
+        cms->d.authEnvelopedData->version = 0;
+        cms->d.authEnvelopedData->authEncryptedContentInfo->contentType =
+            OBJ_nid2obj(NID_pkcs7_data);
+        ASN1_OBJECT_free(cms->contentType);
+        cms->contentType = OBJ_nid2obj(NID_id_smime_ct_authEnvelopedData);
+        return cms->d.authEnvelopedData;
+    }
+    return cms_get0_auth_enveloped(cms);
+}
+
 int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd)
 {
     EVP_PKEY *pkey;
@@ -86,13 +134,32 @@ int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd)
     return 1;
 }
 
+CMS_EncryptedContentInfo* cms_get0_env_enc_content(const CMS_ContentInfo *cms)
+{
+    switch (cms_get_enveloped_type(cms)) {
+    case CMS_ENVELOPED_STANDARD:
+        return cms->d.envelopedData->encryptedContentInfo;
+
+    case CMS_ENVELOPED_AUTH:
+        return cms->d.authEnvelopedData->authEncryptedContentInfo;
+
+    default:
+        return NULL;
+    }
+}
+
 STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms)
 {
-    CMS_EnvelopedData *env;
-    env = cms_get0_enveloped(cms);
-    if (!env)
+    switch (cms_get_enveloped_type(cms)) {
+    case CMS_ENVELOPED_STANDARD:
+        return cms->d.envelopedData->recipientInfos;
+
+    case CMS_ENVELOPED_AUTH:
+        return cms->d.authEnvelopedData->recipientInfos;
+
+    default:
         return NULL;
-    return env->recipientInfos;
+    }
 }
 
 void cms_RecipientInfos_set_cmsctx(CMS_ContentInfo *cms)
@@ -169,45 +236,34 @@ CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher)
     return CMS_EnvelopedData_create_with_libctx(cipher, NULL, NULL);
 }
 
-int cms_EnvelopedData_final(CMS_ContentInfo *cms, BIO *chain)
+CMS_ContentInfo *
+CMS_AuthEnvelopedData_create_with_libctx(const EVP_CIPHER *cipher,
+                                         OPENSSL_CTX *libctx,
+                                         const char *propq)
 {
-    CMS_EnvelopedData *env = NULL;
-    EVP_CIPHER_CTX *ctx = NULL;
-    BIO *mbio = BIO_find_type(chain, BIO_TYPE_CIPHER);
-
-    env = cms_get0_enveloped(cms);
-    if (env == NULL)
-        return 0;
-
-    if (mbio == NULL) {
-        CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, CMS_R_CONTENT_NOT_FOUND);
-        return 0;
-    }
-
-    BIO_get_cipher_ctx(mbio, &ctx);
-
-    /*
-     * If the selected cipher supports unprotected attributes,
-     * deal with it using special ctrl function
-     */
-    if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_CIPHER_WITH_MAC) {
-        if (cms->d.envelopedData->unprotectedAttrs == NULL)
-            cms->d.envelopedData->unprotectedAttrs = sk_X509_ATTRIBUTE_new_null();
+    CMS_ContentInfo *cms;
+    CMS_AuthEnvelopedData *aenv;
 
-        if (cms->d.envelopedData->unprotectedAttrs == NULL) {
-            CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, ERR_R_MALLOC_FAILURE);
-            return 0;
-        }
+    cms = CMS_ContentInfo_new_with_libctx(libctx, propq);
+    if (cms == NULL)
+        goto merr;
+    aenv = cms_auth_enveloped_data_init(cms);
+    if (aenv == NULL)
+        goto merr;
+    if (!cms_EncryptedContent_init(aenv->authEncryptedContentInfo,
+                                   cipher, NULL, 0, cms_get0_cmsctx(cms)))
+        goto merr;
+    return cms;
+ merr:
+    CMS_ContentInfo_free(cms);
+    CMSerr(0, ERR_R_MALLOC_FAILURE);
+    return NULL;
+}
 
-        if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_PROCESS_UNPROTECTED,
-                                1, env->unprotectedAttrs) <= 0) {
-            CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, CMS_R_CTRL_FAILURE);
-            return 0;
-        }
-    }
 
-    cms_env_set_version(cms->d.envelopedData);
-    return 1;
+CMS_ContentInfo *CMS_AuthEnvelopedData_create(const EVP_CIPHER *cipher)
+{
+    return CMS_AuthEnvelopedData_create_with_libctx(cipher, NULL, NULL);
 }
 
 /* Key Transport Recipient Info (KTRI) routines */
@@ -272,17 +328,17 @@ CMS_RecipientInfo *CMS_add1_recipient(CMS_ContentInfo *cms, X509 *recip,
                                       X509 *originator, unsigned int flags)
 {
     CMS_RecipientInfo *ri = NULL;
-    CMS_EnvelopedData *env;
+    STACK_OF(CMS_RecipientInfo) *ris;
     EVP_PKEY *pk = NULL;
     const CMS_CTX *ctx = cms_get0_cmsctx(cms);
 
-    env = cms_get0_enveloped(cms);
-    if (!env)
+    ris = CMS_get0_RecipientInfos(cms);
+    if (ris == NULL)
         goto err;
 
     /* Initialize recipient info */
     ri = M_ASN1_new_of(CMS_RecipientInfo);
-    if (!ri)
+    if (ri == NULL)
         goto merr;
 
     pk = X509_get0_pubkey(recip);
@@ -311,7 +367,7 @@ CMS_RecipientInfo *CMS_add1_recipient(CMS_ContentInfo *cms, X509 *recip,
 
     }
 
-    if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
+    if (!sk_CMS_RecipientInfo_push(ris, ri))
         goto merr;
 
     return ri;
@@ -324,8 +380,8 @@ CMS_RecipientInfo *CMS_add1_recipient(CMS_ContentInfo *cms, X509 *recip,
 
 }
 
-CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms,
-     X509 *recip, unsigned int flags)
+CMS_RecipientInfo *CMS_add1_recipient_cert(CMS_ContentInfo *cms, X509 *recip,
+                                           unsigned int flags)
 {
      return CMS_add1_recipient(cms, recip, NULL, NULL, flags);
 }
@@ -408,7 +464,7 @@ static int cms_RecipientInfo_ktri_encrypt(const CMS_ContentInfo *cms,
         return 0;
     }
     ktri = ri->d.ktri;
-    ec = cms->d.envelopedData->encryptedContentInfo;
+    ec = cms_get0_env_enc_content(cms);
 
     pctx = ktri->pctx;
 
@@ -471,7 +527,7 @@ static int cms_RecipientInfo_ktri_decrypt(CMS_ContentInfo *cms,
     CMS_EncryptedContentInfo *ec;
     const CMS_CTX *ctx = cms_get0_cmsctx(cms);
 
-    ec = cms->d.envelopedData->encryptedContentInfo;
+    ec = cms_get0_env_enc_content(cms);
 
     if (ktri->pkey == NULL) {
         CMSerr(CMS_F_CMS_RECIPIENTINFO_KTRI_DECRYPT, CMS_R_NO_PRIVATE_KEY);
@@ -598,10 +654,10 @@ CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid,
                                           ASN1_TYPE *otherType)
 {
     CMS_RecipientInfo *ri = NULL;
-    CMS_EnvelopedData *env;
     CMS_KEKRecipientInfo *kekri;
-    env = cms_get0_enveloped(cms);
-    if (!env)
+    STACK_OF(CMS_RecipientInfo) *ris = CMS_get0_RecipientInfos(cms);
+
+    if (ris == NULL)
         goto err;
 
     if (nid == NID_undef) {
@@ -658,7 +714,7 @@ CMS_RecipientInfo *CMS_add0_recipient_key(CMS_ContentInfo *cms, int nid,
             goto merr;
     }
 
-    if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
+    if (!sk_CMS_RecipientInfo_push(ris, ri))
         goto merr;
 
     /* After this point no calls can fail */
@@ -774,7 +830,9 @@ static int cms_RecipientInfo_kekri_encrypt(const CMS_ContentInfo *cms,
     EVP_CIPHER_CTX *ctx = NULL;
     const CMS_CTX *cms_ctx = cms_get0_cmsctx(cms);
 
-    ec = cms->d.envelopedData->encryptedContentInfo;
+    ec = cms_get0_env_enc_content(cms);
+    if (ec == NULL)
+        return 0;
 
     kekri = ri->d.kekri;
 
@@ -843,7 +901,9 @@ static int cms_RecipientInfo_kekri_decrypt(CMS_ContentInfo *cms,
     EVP_CIPHER_CTX *ctx = NULL;
     const CMS_CTX *cms_ctx = cms_get0_cmsctx(cms);
 
-    ec = cms->d.envelopedData->encryptedContentInfo;
+    ec = cms_get0_env_enc_content(cms);
+    if (ec == NULL)
+        return 0;
 
     kekri = ri->d.kekri;
 
@@ -1013,6 +1073,28 @@ static void cms_env_set_version(CMS_EnvelopedData *env)
     env->version = 0;
 }
 
+static int cms_env_encrypt_content_key(const CMS_ContentInfo *cms,
+                                       STACK_OF(CMS_RecipientInfo) *ris)
+{
+    int i;
+    CMS_RecipientInfo *ri;
+
+    for (i = 0; i < sk_CMS_RecipientInfo_num(ris); i++) {
+        ri = sk_CMS_RecipientInfo_value(ris, i);
+        if (CMS_RecipientInfo_encrypt(cms, ri) <= 0)
+            return -1;
+    }
+    return 1;
+}
+
+static void cms_env_clear_ec(CMS_EncryptedContentInfo *ec)
+{
+    ec->cipher = NULL;
+    OPENSSL_clear_free(ec->key, ec->keylen);
+    ec->key = NULL;
+    ec->keylen = 0;
+}
+
 static BIO *cms_EnvelopedData_Decryption_init_bio(CMS_ContentInfo *cms)
 {
     CMS_EncryptedContentInfo *ec = cms->d.envelopedData->encryptedContentInfo;
@@ -1027,10 +1109,10 @@ static BIO *cms_EnvelopedData_Decryption_init_bio(CMS_ContentInfo *cms)
         BIO_free(contentBio);
         return NULL;
     }
-/*
- * If the selected cipher supports unprotected attributes,
- * deal with it using special ctrl function
- */
+    /*
+     * If the selected cipher supports unprotected attributes,
+     * deal with it using special ctrl function
+     */
     if ((EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_CIPHER_WITH_MAC)
          && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_PROCESS_UNPROTECTED, 0,
                                 cms->d.envelopedData->unprotectedAttrs) <= 0) {
@@ -1044,13 +1126,13 @@ static BIO *cms_EnvelopedData_Encryption_init_bio(CMS_ContentInfo *cms)
 {
     CMS_EncryptedContentInfo *ec;
     STACK_OF(CMS_RecipientInfo) *rinfos;
-    CMS_RecipientInfo *ri;
-    int i, ok = 0;
+    int ok = 0;
     BIO *ret;
+    CMS_EnvelopedData *env = cms->d.envelopedData;
 
     /* Get BIO first to set up key */
 
-    ec = cms->d.envelopedData->encryptedContentInfo;
+    ec = env->encryptedContentInfo;
     ret = cms_EncryptedContent_init_bio(ec, cms_get0_cmsctx(cms));
 
     /* If error end of processing */
@@ -1058,24 +1140,20 @@ static BIO *cms_EnvelopedData_Encryption_init_bio(CMS_ContentInfo *cms)
         return ret;
 
     /* Now encrypt content key according to each RecipientInfo type */
-    rinfos = cms->d.envelopedData->recipientInfos;
-
-    for (i = 0; i < sk_CMS_RecipientInfo_num(rinfos); i++) {
-         ri = sk_CMS_RecipientInfo_value(rinfos, i);
-         if (CMS_RecipientInfo_encrypt(cms, ri) <= 0) {
-             CMSerr(0, CMS_R_ERROR_SETTING_RECIPIENTINFO);
-             goto err;
-         }
+    rinfos = env->recipientInfos;
+    if (cms_env_encrypt_content_key(cms, rinfos) < 0) {
+        CMSerr(CMS_F_CMS_ENVELOPEDDATA_ENCRYPTION_INIT_BIO,
+               CMS_R_ERROR_SETTING_RECIPIENTINFO);
+        goto err;
     }
-    cms_env_set_version(cms->d.envelopedData);
+
+    /* And finally set the version */
+    cms_env_set_version(env);
 
     ok = 1;
 
  err:
-    ec->cipher = NULL;
-    OPENSSL_clear_free(ec->key, ec->keylen);
-    ec->key = NULL;
-    ec->keylen = 0;
+    cms_env_clear_ec(ec);
     if (ok)
         return ret;
     BIO_free(ret);
@@ -1093,6 +1171,121 @@ BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms)
     return cms_EnvelopedData_Decryption_init_bio(cms);
 }
 
+BIO *cms_AuthEnvelopedData_init_bio(CMS_ContentInfo *cms)
+{
+    CMS_EncryptedContentInfo *ec;
+    STACK_OF(CMS_RecipientInfo) *rinfos;
+    int ok = 0;
+    BIO *ret;
+    CMS_AuthEnvelopedData *aenv = cms->d.authEnvelopedData;
+
+    /* Get BIO first to set up key */
+    ec = aenv->authEncryptedContentInfo;
+    /* Set tag for decryption */
+    if (ec->cipher == NULL) {
+        ec->tag = aenv->mac->data;
+        ec->taglen = aenv->mac->length;
+    }
+    ret = cms_EncryptedContent_init_bio(ec, cms_get0_cmsctx(cms));
+
+    /* If error or no cipher end of processing */
+    if (ret == NULL || ec->cipher == NULL)
+        return ret;
+
+    /* Now encrypt content key according to each RecipientInfo type */
+    rinfos = aenv->recipientInfos;
+    if (cms_env_encrypt_content_key(cms, rinfos) < 0) {
+        CMSerr(0, CMS_R_ERROR_SETTING_RECIPIENTINFO);
+        goto err;
+    }
+
+    /* And finally set the version */
+    aenv->version = 0;
+
+    ok = 1;
+
+ err:
+    cms_env_clear_ec(ec);
+    if (ok)
+        return ret;
+    BIO_free(ret);
+    return NULL;
+}
+
+int cms_EnvelopedData_final(CMS_ContentInfo *cms, BIO *chain)
+{
+    CMS_EnvelopedData *env = NULL;
+    EVP_CIPHER_CTX *ctx = NULL;
+    BIO *mbio = BIO_find_type(chain, BIO_TYPE_CIPHER);
+
+    env = cms_get0_enveloped(cms);
+    if (env == NULL)
+        return 0;
+
+    if (mbio == NULL) {
+        CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, CMS_R_CONTENT_NOT_FOUND);
+        return 0;
+    }
+
+    BIO_get_cipher_ctx(mbio, &ctx);
+
+    /*
+     * If the selected cipher supports unprotected attributes,
+     * deal with it using special ctrl function
+     */
+    if (EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(ctx)) & EVP_CIPH_FLAG_CIPHER_WITH_MAC) {
+        if (env->unprotectedAttrs == NULL)
+            env->unprotectedAttrs = sk_X509_ATTRIBUTE_new_null();
+
+        if (env->unprotectedAttrs == NULL) {
+            CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+
+        if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_PROCESS_UNPROTECTED,
+                                1, env->unprotectedAttrs) <= 0) {
+            CMSerr(CMS_F_CMS_ENVELOPEDDATA_FINAL, CMS_R_CTRL_FAILURE);
+            return 0;
+        }
+    }
+
+    cms_env_set_version(cms->d.envelopedData);
+    return 1;
+}
+
+int cms_AuthEnvelopedData_final(CMS_ContentInfo *cms, BIO *cmsbio)
+{
+    EVP_CIPHER_CTX *ctx;
+    unsigned char *tag = NULL;
+    int taglen, ok = 0;
+
+    BIO_get_cipher_ctx(cmsbio, &ctx);
+
+    /* 
+     * The tag is set only for encryption. There is nothing to do for
+     * decryption.
+     */
+    if (!EVP_CIPHER_CTX_encrypting(ctx))
+        return 1;
+
+    taglen = EVP_CIPHER_CTX_tag_length(ctx);
+    if (taglen <= 0
+            || (tag = OPENSSL_malloc(taglen)) == NULL
+            || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen,
+                                   tag) <= 0) {
+        CMSerr(0, CMS_R_CIPHER_GET_TAG);
+        goto err;
+    }
+
+    if (!ASN1_OCTET_STRING_set(cms->d.authEnvelopedData->mac, tag, taglen))
+        goto err;
+
+    ok = 1;
+err:
+    OPENSSL_free(tag);
+    return ok;
+}
+
 /*
  * Get RecipientInfo type (if any) supported by a key (public or private). To
  * retain compatibility with previous behaviour if the ctrl value isn't
diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c
index 16e25afc7f..da14c726c4 100644
--- a/crypto/cms/cms_err.c
+++ b/crypto/cms/cms_err.c
@@ -22,6 +22,9 @@ static const ERR_STRING_DATA CMS_str_reasons[] = {
     "certificate has no keyid"},
     {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CERTIFICATE_VERIFY_ERROR),
     "certificate verify error"},
+    {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CIPHER_AEAD_SET_TAG_ERROR),
+    "cipher aead set tag error"},
+    {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CIPHER_GET_TAG), "cipher get tag"},
     {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CIPHER_INITIALISATION_ERROR),
     "cipher initialisation error"},
     {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR),
diff --git a/crypto/cms/cms_kari.c b/crypto/cms/cms_kari.c
index 97b601b3bc..b5d85b7d67 100644
--- a/crypto/cms/cms_kari.c
+++ b/crypto/cms/cms_kari.c
@@ -291,7 +291,7 @@ int CMS_RecipientInfo_kari_decrypt(CMS_ContentInfo *cms,
     /* Attempt to decrypt CEK */
     if (!cms_kek_cipher(&cek, &ceklen, enckey, enckeylen, ri->d.kari, 0))
         goto err;
-    ec = cms->d.envelopedData->encryptedContentInfo;
+    ec = cms_get0_env_enc_content(cms);
     OPENSSL_clear_free(ec->key, ec->keylen);
     ec->key = cek;
     ec->keylen = ceklen;
@@ -533,7 +533,7 @@ int cms_RecipientInfo_kari_encrypt(const CMS_ContentInfo *cms,
     }
     kari = ri->d.kari;
     reks = kari->recipientEncryptedKeys;
-    ec = cms->d.envelopedData->encryptedContentInfo;
+    ec = cms_get0_env_enc_content(cms);
     /* Initialise wrap algorithm parameters */
     if (!cms_wrap_init(kari, ec->cipher))
         return 0;
diff --git a/crypto/cms/cms_lib.c b/crypto/cms/cms_lib.c
index 7c9b2494a2..9fc8453d99 100644
--- a/crypto/cms/cms_lib.c
+++ b/crypto/cms/cms_lib.c
@@ -189,6 +189,10 @@ BIO *CMS_dataInit(CMS_ContentInfo *cms, BIO *icont)
         cmsbio = cms_EnvelopedData_init_bio(cms);
         break;
 
+    case NID_id_smime_ct_authEnvelopedData:
+        cmsbio = cms_AuthEnvelopedData_init_bio(cms);
+        break;
+
     default:
         CMSerr(CMS_F_CMS_DATAINIT, CMS_R_UNSUPPORTED_TYPE);
         goto err;
@@ -239,6 +243,9 @@ int CMS_dataFinal(CMS_ContentInfo *cms, BIO *cmsbio)
     case NID_pkcs7_enveloped:
         return cms_EnvelopedData_final(cms, cmsbio);
 
+    case NID_id_smime_ct_authEnvelopedData:
+        return cms_AuthEnvelopedData_final(cms, cmsbio);
+
     case NID_pkcs7_signed:
         return cms_SignedData_final(cms, cmsbio);
 
@@ -275,6 +282,10 @@ ASN1_OCTET_STRING **CMS_get0_content(CMS_ContentInfo *cms)
     case NID_pkcs7_encrypted:
         return &cms->d.encryptedData->encryptedContentInfo->encryptedContent;
 
+    case NID_id_smime_ct_authEnvelopedData:
+        return &cms->d.authEnvelopedData->authEncryptedContentInfo
+                                        ->encryptedContent;
+
     case NID_id_smime_ct_authData:
         return &cms->d.authenticatedData->encapContentInfo->eContent;
 
@@ -311,6 +322,9 @@ static ASN1_OBJECT **cms_get0_econtent_type(CMS_ContentInfo *cms)
     case NID_pkcs7_encrypted:
         return &cms->d.encryptedData->encryptedContentInfo->contentType;
 
+    case NID_id_smime_ct_authEnvelopedData:
+        return &cms->d.authEnvelopedData->authEncryptedContentInfo
+                                        ->contentType;
     case NID_id_smime_ct_authData:
         return &cms->d.authenticatedData->encapContentInfo->eContentType;
 
@@ -472,6 +486,11 @@ static STACK_OF(CMS_CertificateChoices)
             return NULL;
         return &cms->d.envelopedData->originatorInfo->certificates;
 
+    case NID_id_smime_ct_authEnvelopedData:
+        if (cms->d.authEnvelopedData->originatorInfo == NULL)
+            return NULL;
+        return &cms->d.authEnvelopedData->originatorInfo->certificates;
+
     default:
         CMSerr(CMS_F_CMS_GET0_CERTIFICATE_CHOICES,
                CMS_R_UNSUPPORTED_CONTENT_TYPE);
@@ -551,6 +570,11 @@ static STACK_OF(CMS_RevocationInfoChoice)
             return NULL;
         return &cms->d.envelopedData->originatorInfo->crls;
 
+    case NID_id_smime_ct_authEnvelopedData:
+        if (cms->d.authEnvelopedData->originatorInfo == NULL)
+            return NULL;
+        return &cms->d.authEnvelopedData->originatorInfo->crls;
+
     default:
         CMSerr(CMS_F_CMS_GET0_REVOCATION_CHOICES,
                CMS_R_UNSUPPORTED_CONTENT_TYPE);
diff --git a/crypto/cms/cms_local.h b/crypto/cms/cms_local.h
index 4e85459a54..336c354655 100644
--- a/crypto/cms/cms_local.h
+++ b/crypto/cms/cms_local.h
@@ -29,6 +29,7 @@ typedef struct CMS_EnvelopedData_st CMS_EnvelopedData;
 typedef struct CMS_DigestedData_st CMS_DigestedData;
 typedef struct CMS_EncryptedData_st CMS_EncryptedData;
 typedef struct CMS_AuthenticatedData_st CMS_AuthenticatedData;
+typedef struct CMS_AuthEnvelopedData_st CMS_AuthEnvelopedData;
 typedef struct CMS_CompressedData_st CMS_CompressedData;
 typedef struct CMS_OtherCertificateFormat_st CMS_OtherCertificateFormat;
 typedef struct CMS_KeyTransRecipientInfo_st CMS_KeyTransRecipientInfo;
@@ -58,6 +59,7 @@ struct CMS_ContentInfo_st {
         CMS_EnvelopedData *envelopedData;
         CMS_DigestedData *digestedData;
         CMS_EncryptedData *encryptedData;
+        CMS_AuthEnvelopedData *authEnvelopedData;
         CMS_AuthenticatedData *authenticatedData;
         CMS_CompressedData *compressedData;
         ASN1_TYPE *other;
@@ -127,10 +129,12 @@ struct CMS_EncryptedContentInfo_st {
     ASN1_OBJECT *contentType;
     X509_ALGOR *contentEncryptionAlgorithm;
     ASN1_OCTET_STRING *encryptedContent;
-    /* Content encryption algorithm and key */
+    /* Content encryption algorithm, key and tag */
     const EVP_CIPHER *cipher;
     unsigned char *key;
     size_t keylen;
+    unsigned char *tag;
+    size_t taglen;
     /* Set to 1 if we are debugging decrypt and don't fake keys for MMA */
     int debug;
     /* Set to 1 if we have no cert and need extra safety measures for MMA */
@@ -269,6 +273,16 @@ struct CMS_AuthenticatedData_st {
     STACK_OF(X509_ATTRIBUTE) *unauthAttrs;
 };
 
+struct CMS_AuthEnvelopedData_st {
+    int32_t version;
+    CMS_OriginatorInfo *originatorInfo;
+    STACK_OF(CMS_RecipientInfo) *recipientInfos;
+    CMS_EncryptedContentInfo *authEncryptedContentInfo;
+    STACK_OF(X509_ATTRIBUTE) *authAttrs;
+    ASN1_OCTET_STRING *mac;
+    STACK_OF(X509_ATTRIBUTE) *unauthAttrs;
+};
+
 struct CMS_CompressedData_st {
     int32_t version;
     X509_ALGOR *compressionAlgorithm;
@@ -425,7 +439,11 @@ ASN1_OCTET_STRING *cms_encode_Receipt(CMS_SignerInfo *si);
 
 BIO *cms_EnvelopedData_init_bio(CMS_ContentInfo *cms);
 int cms_EnvelopedData_final(CMS_ContentInfo *cms, BIO *chain);
+BIO *cms_AuthEnvelopedData_init_bio(CMS_ContentInfo *cms);
+int cms_AuthEnvelopedData_final(CMS_ContentInfo *cms, BIO *cmsbio);
 CMS_EnvelopedData *cms_get0_enveloped(CMS_ContentInfo *cms);
+CMS_AuthEnvelopedData *cms_get0_auth_enveloped(CMS_ContentInfo *cms);
+CMS_EncryptedContentInfo* cms_get0_env_enc_content(const CMS_ContentInfo *cms);
 
 /* RecipientInfo routines */
 int cms_env_asn1_ctrl(CMS_RecipientInfo *ri, int cmd);
@@ -457,6 +475,7 @@ DECLARE_ASN1_ITEM(CMS_CertificateChoices)
 DECLARE_ASN1_ITEM(CMS_DigestedData)
 DECLARE_ASN1_ITEM(CMS_EncryptedData)
 DECLARE_ASN1_ITEM(CMS_EnvelopedData)
+DECLARE_ASN1_ITEM(CMS_AuthEnvelopedData)
 DECLARE_ASN1_ITEM(CMS_KEKRecipientInfo)
 DECLARE_ASN1_ITEM(CMS_KeyAgreeRecipientInfo)
 DECLARE_ASN1_ITEM(CMS_KeyTransRecipientInfo)
diff --git a/crypto/cms/cms_pwri.c b/crypto/cms/cms_pwri.c
index 1ca5a7ee07..e281bd72f2 100644
--- a/crypto/cms/cms_pwri.c
+++ b/crypto/cms/cms_pwri.c
@@ -44,8 +44,9 @@ CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
                                                ossl_ssize_t passlen,
                                                const EVP_CIPHER *kekciph)
 {
+    STACK_OF(CMS_RecipientInfo) *ris;
     CMS_RecipientInfo *ri = NULL;
-    CMS_EnvelopedData *env;
+    CMS_EncryptedContentInfo *ec;
     CMS_PasswordRecipientInfo *pwri;
     EVP_CIPHER_CTX *ctx = NULL;
     X509_ALGOR *encalg = NULL;
@@ -53,8 +54,11 @@ CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
     int ivlen;
     const CMS_CTX *cms_ctx = cms_get0_cmsctx(cms);
 
-    env = cms_get0_enveloped(cms);
-    if (!env)
+    ec = cms_get0_env_enc_content(cms);
+    if (ec == NULL)
+        return NULL;
+    ris = CMS_get0_RecipientInfos(cms);
+    if (ris == NULL)
         return NULL;
 
     if (wrap_nid <= 0)
@@ -65,7 +69,7 @@ CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
 
     /* Get from enveloped data */
     if (kekciph == NULL)
-        kekciph = env->encryptedContentInfo->cipher;
+        kekciph = ec->cipher;
 
     if (kekciph == NULL) {
         CMSerr(CMS_F_CMS_ADD0_RECIPIENT_PASSWORD, CMS_R_NO_CIPHER);
@@ -156,7 +160,7 @@ CMS_RecipientInfo *CMS_add0_recipient_password(CMS_ContentInfo *cms,
     CMS_RecipientInfo_set0_password(ri, pass, passlen);
     pwri->version = 0;
 
-    if (!sk_CMS_RecipientInfo_push(env->recipientInfos, ri))
+    if (!sk_CMS_RecipientInfo_push(ris, ri))
         goto merr;
 
     return ri;
@@ -292,7 +296,7 @@ int cms_RecipientInfo_pwri_crypt(const CMS_ContentInfo *cms,
     size_t keylen;
     const CMS_CTX *cms_ctx = cms_get0_cmsctx(cms);
 
-    ec = cms->d.envelopedData->encryptedContentInfo;
+    ec = cms_get0_env_enc_content(cms);
 
     pwri = ri->d.pwri;
 
diff --git a/crypto/cms/cms_smime.c b/crypto/cms/cms_smime.c
index 11c9fed1a8..92de68aa57 100644
--- a/crypto/cms/cms_smime.c
+++ b/crypto/cms/cms_smime.c
@@ -638,7 +638,10 @@ CMS_ContentInfo *CMS_encrypt_with_libctx(STACK_OF(X509) *certs,
     int i;
     X509 *recip;
 
-    cms = CMS_EnvelopedData_create_with_libctx(cipher, libctx, propq);
+
+    cms = (EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)
+          ? CMS_AuthEnvelopedData_create_with_libctx(cipher, libctx, propq)
+          : CMS_EnvelopedData_create_with_libctx(cipher, libctx, propq);
     if (cms == NULL)
         goto merr;
     for (i = 0; i < sk_X509_num(certs); i++) {
@@ -711,7 +714,7 @@ int CMS_decrypt_set1_pkey_and_peer(CMS_ContentInfo *cms, EVP_PKEY *pk,
 
     ris = CMS_get0_RecipientInfos(cms);
     if (ris != NULL)
-        debug = cms->d.envelopedData->encryptedContentInfo->debug;
+        debug = cms_get0_env_enc_content(cms)->debug;
 
     cms_pkey_ri_type = cms_pkey_get_ri_type(pk);
     if (cms_pkey_ri_type == CMS_RECIPINFO_NONE) {
@@ -848,20 +851,23 @@ 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) {
+    int nid = OBJ_obj2nid(CMS_get0_type(cms));
+
+    if (nid != NID_pkcs7_enveloped
+            && nid != NID_id_smime_ct_authEnvelopedData) {
         CMSerr(CMS_F_CMS_DECRYPT, CMS_R_TYPE_NOT_ENVELOPED_DATA);
         return 0;
     }
     if (dcont == NULL && !check_content(cms))
         return 0;
     if (flags & CMS_DEBUG_DECRYPT)
-        cms->d.envelopedData->encryptedContentInfo->debug = 1;
+        cms_get0_env_enc_content(cms)->debug = 1;
     else
-        cms->d.envelopedData->encryptedContentInfo->debug = 0;
+        cms_get0_env_enc_content(cms)->debug = 0;
     if (cert == NULL)
-        cms->d.envelopedData->encryptedContentInfo->havenocert = 1;
+        cms_get0_env_enc_content(cms)->havenocert = 1;
     else
-        cms->d.envelopedData->encryptedContentInfo->havenocert = 0;
+        cms_get0_env_enc_content(cms)->havenocert = 0;
     if (pk == NULL && cert == NULL && dcont == NULL && out == NULL)
         return 1;
     if (pk != NULL && !CMS_decrypt_set1_pkey(cms, pk, cert))
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 256ec35588..44e36805f6 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -63,6 +63,7 @@ ASN1_F_ASN1_TEMPLATE_NOEXP_D2I:131:asn1_template_noexp_d2i
 ASN1_F_ASN1_TIME_ADJ:217:ASN1_TIME_adj
 ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING:134:ASN1_TYPE_get_int_octetstring
 ASN1_F_ASN1_TYPE_GET_OCTETSTRING:135:ASN1_TYPE_get_octetstring
+ASN1_F_ASN1_TYPE_GET_OCTETSTRING_INT:146:
 ASN1_F_ASN1_UTCTIME_ADJ:218:ASN1_UTCTIME_adj
 ASN1_F_ASN1_VERIFY:137:ASN1_verify
 ASN1_F_B64_READ_ASN1:209:b64_read_asn1
@@ -2172,6 +2173,8 @@ CMS_R_ATTRIBUTE_ERROR:161:attribute error
 CMS_R_CERTIFICATE_ALREADY_PRESENT:175:certificate already present
 CMS_R_CERTIFICATE_HAS_NO_KEYID:160:certificate has no keyid
 CMS_R_CERTIFICATE_VERIFY_ERROR:100:certificate verify error
+CMS_R_CIPHER_AEAD_SET_TAG_ERROR:184:cipher aead set tag error
+CMS_R_CIPHER_GET_TAG:185:cipher get tag
 CMS_R_CIPHER_INITIALISATION_ERROR:101:cipher initialisation error
 CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR:102:\
 	cipher parameter initialisation error
diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c
index 676461a51b..81151e4f01 100644
--- a/crypto/evp/evp_lib.c
+++ b/crypto/evp/evp_lib.c
@@ -22,11 +22,59 @@
 #include <openssl/dh.h>
 #include <openssl/ec.h>
 #include "crypto/evp.h"
+#include "crypto/asn1.h"
 #include "internal/provider.h"
 #include "evp_local.h"
 
 #if !defined(FIPS_MODULE)
 int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
+{
+    return evp_cipher_param_to_asn1_ex(c, type, NULL);
+}
+
+int EVP_CIPHER_asn1_to_param(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
+{
+    return evp_cipher_asn1_to_param_ex(c, type, NULL);
+}
+
+int EVP_CIPHER_get_asn1_iv(EVP_CIPHER_CTX *ctx, ASN1_TYPE *type)
+{
+    int i = 0;
+    unsigned int l;
+
+    if (type != NULL) {
+        unsigned char iv[EVP_MAX_IV_LENGTH];
+
+        l = EVP_CIPHER_CTX_iv_length(ctx);
+        if (!ossl_assert(l <= sizeof(iv)))
+            return -1;
+        i = ASN1_TYPE_get_octetstring(type, iv, l);
+        if (i != (int)l)
+            return -1;
+
+        if (!EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, -1))
+            return -1;
+    }
+    return i;
+}
+
+int EVP_CIPHER_set_asn1_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
+{
+    int i = 0;
+    unsigned int j;
+    unsigned char *oiv = NULL;
+
+    if (type != NULL) {
+        oiv = (unsigned char *)EVP_CIPHER_CTX_original_iv(c);
+        j = EVP_CIPHER_CTX_iv_length(c);
+        OPENSSL_assert(j <= sizeof(c->iv));
+        i = ASN1_TYPE_set_octetstring(type, oiv, j);
+    }
+    return i;
+}
+
+int evp_cipher_param_to_asn1_ex(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
+                                evp_cipher_aead_asn1_params *asn1_params)
 {
     int ret = -1;                /* Assume the worst */
     const EVP_CIPHER *cipher = c->cipher;
@@ -58,6 +106,9 @@ int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
             break;
 
         case EVP_CIPH_GCM_MODE:
+            ret = evp_cipher_set_asn1_aead_params(c, type, asn1_params);
+            break;
+
         case EVP_CIPH_CCM_MODE:
         case EVP_CIPH_XTS_MODE:
         case EVP_CIPH_OCB_MODE:
@@ -104,15 +155,16 @@ int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
 
  err:
     if (ret == -2)
-        EVPerr(EVP_F_EVP_CIPHER_PARAM_TO_ASN1, ASN1_R_UNSUPPORTED_CIPHER);
+        EVPerr(0, EVP_R_UNSUPPORTED_CIPHER);
     else if (ret <= 0)
-        EVPerr(EVP_F_EVP_CIPHER_PARAM_TO_ASN1, EVP_R_CIPHER_PARAMETER_ERROR);
+        EVPerr(0, EVP_R_CIPHER_PARAMETER_ERROR);
     if (ret < -1)
         ret = -1;
     return ret;
 }
 
-int EVP_CIPHER_asn1_to_param(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
+int evp_cipher_asn1_to_param_ex(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
+                                evp_cipher_aead_asn1_params *asn1_params)
 {
     int ret = -1;                /* Assume the worst */
     const EVP_CIPHER *cipher = c->cipher;
@@ -142,6 +194,9 @@ int EVP_CIPHER_asn1_to_param(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
             break;
 
         case EVP_CIPH_GCM_MODE:
+            ret = evp_cipher_get_asn1_aead_params(c, type, asn1_params);
+            break;
+
         case EVP_CIPH_CCM_MODE:
         case EVP_CIPH_XTS_MODE:
         case EVP_CIPH_OCB_MODE:
@@ -170,47 +225,43 @@ int EVP_CIPHER_asn1_to_param(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
     }
 
     if (ret == -2)
-        EVPerr(EVP_F_EVP_CIPHER_ASN1_TO_PARAM, EVP_R_UNSUPPORTED_CIPHER);
+        EVPerr(0, EVP_R_UNSUPPORTED_CIPHER);
     else if (ret <= 0)
-        EVPerr(EVP_F_EVP_CIPHER_ASN1_TO_PARAM, EVP_R_CIPHER_PARAMETER_ERROR);
+        EVPerr(0, EVP_R_CIPHER_PARAMETER_ERROR);
     if (ret < -1)
         ret = -1;
     return ret;
 }
 
-int EVP_CIPHER_get_asn1_iv(EVP_CIPHER_CTX *ctx, ASN1_TYPE *type)
+int evp_cipher_get_asn1_aead_params(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
+                                    evp_cipher_aead_asn1_params *asn1_params)
 {
     int i = 0;
-    unsigned int l;
+    long tl;
+    unsigned char iv[EVP_MAX_IV_LENGTH];
 
-    if (type != NULL) {
-        unsigned char iv[EVP_MAX_IV_LENGTH];
+    if (type == NULL || asn1_params == NULL)
+        return 0;
 
-        l = EVP_CIPHER_CTX_iv_length(ctx);
-        if (!ossl_assert(l <= sizeof(iv)))
-            return -1;
-        i = ASN1_TYPE_get_octetstring(type, iv, l);
-        if (i != (int)l)
-            return -1;
+    i = asn1_type_get_octetstring_int(type, &tl, NULL, EVP_MAX_IV_LENGTH);
+    if (i <= 0)
+        return -1;
+    asn1_type_get_octetstring_int(type, &tl, iv, i);
+
+    memcpy(asn1_params->iv, iv, i);
+    asn1_params->iv_len = i;
 
-        if (!EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv, -1))
-            return -1;
-    }
     return i;
 }
 
-int EVP_CIPHER_set_asn1_iv(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
+int evp_cipher_set_asn1_aead_params(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
+                                    evp_cipher_aead_asn1_params *asn1_params)
 {
-    int i = 0;
-    unsigned int j;
-    unsigned char oiv[EVP_MAX_IV_LENGTH];
+    if (type == NULL || asn1_params == NULL)
+        return 0;
 
-    if (type != NULL && EVP_CIPHER_CTX_get_iv(c, oiv, sizeof(oiv))) {
-        j = EVP_CIPHER_CTX_iv_length(c);
-        OPENSSL_assert(j <= sizeof(c->iv));
-        i = ASN1_TYPE_set_octetstring(type, oiv, j);
-    }
-    return i;
+    return asn1_type_set_octetstring_int(type, asn1_params->tag_len,
+                                         asn1_params->iv, asn1_params->iv_len);
 }
 #endif /* !defined(FIPS_MODULE) */
 
diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h
index 1e1d689070..e7f7643d83 100644
--- a/crypto/evp/evp_local.h
+++ b/crypto/evp/evp_local.h
@@ -240,6 +240,11 @@ EVP_KEYMGMT *evp_keymgmt_fetch_by_number(OPENSSL_CTX *ctx, int name_id,
 EVP_MD *evp_md_new(void);
 EVP_CIPHER *evp_cipher_new(void);
 
+int evp_cipher_get_asn1_aead_params(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
+                                    evp_cipher_aead_asn1_params *asn1_params);
+int evp_cipher_set_asn1_aead_params(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
+                                    evp_cipher_aead_asn1_params *asn1_params);
+
 /* Helper functions to avoid duplicating code */
 
 /*
diff --git a/doc/man1/openssl-cms.pod.in b/doc/man1/openssl-cms.pod.in
index def9766b3c..ebe3fbda8c 100644
--- a/doc/man1/openssl-cms.pod.in
+++ b/doc/man1/openssl-cms.pod.in
@@ -309,6 +309,9 @@ EVP_get_cipherbyname() function) can also be used preceded by a dash, for
 example B<-aes-128-cbc>. See L<openssl-enc(1)> for a list of ciphers
 supported by your version of OpenSSL.
 
+Currently the AES variants with GCM mode are the only supported AEAD
+algorithms.
+
 If not specified triple DES is used. Only used with B<-encrypt> and
 B<-EncryptedData_create> commands.
 
diff --git a/doc/man3/CMS_EnvelopedData_create.pod b/doc/man3/CMS_EnvelopedData_create.pod
index e6903ea3f8..6978aaabcb 100644
--- a/doc/man3/CMS_EnvelopedData_create.pod
+++ b/doc/man3/CMS_EnvelopedData_create.pod
@@ -2,25 +2,39 @@
 
 =head1 NAME
 
-CMS_EnvelopedData_create_with_libctx, CMS_EnvelopedData_create
+CMS_EnvelopedData_create_with_libctx, CMS_EnvelopedData_create,
+CMS_AuthEnvelopedData_create, CMS_AuthEnvelopedData_create_with_libctx
 - Create CMS envelope
 
 =head1 SYNOPSIS
 
  #include <openssl/cms.h>
 
- CMS_ContentInfo *CMS_EnvelopedData_create_with_libctx(const EVP_CIPHER *cipher,
-                                                       OPENSSL_CTX *libctx,
-                                                       const char *propq);
+ CMS_ContentInfo *
+ CMS_EnvelopedData_create_with_libctx(const EVP_CIPHER *cipher,
+                                      OPENSSL_CTX *libctx,
+                                      const char *propq);
  CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher);
 
+ CMS_ContentInfo *
+ CMS_AuthEnvelopedData_create_with_libctx(const EVP_CIPHER *cipher,
+                                          OPENSSL_CTX *libctx,
+                                          const char *propq);
+ CMS_ContentInfo *CMS_AuthEnvelopedData_create(const EVP_CIPHER *cipher);
+
 =head1 DESCRIPTION
 
-CMS_EnvelopedData_create_with_libctx() creates a B<CMS_ContentInfo> structure with
-a type B<NID_pkcs7_enveloped>. I<cipher> is the symmetric cipher to use. The
-library context I<libctx> and the property query I<propq> are used when
+CMS_EnvelopedData_create_with_libctx() creates a B<CMS_ContentInfo> structure
+with a type B<NID_pkcs7_enveloped>. I<cipher> is the symmetric cipher to use.
+The library context I<libctx> and the property query I<propq> are used when
 retrieving algorithms from providers.
 
+CMS_AuthEnvelopedData_create_with_libctx() creates a B<CMS_ContentInfo>
+structure with a type B<NID_id_smime_ct_authEnvelopedData>. B<cipher> is the
+symmetric AEAD cipher to use. Currently only AES variants with GCM mode are
+supported. The library context I<libctx> and the property query I<propq> are
+used when retrieving algorithms from providers.
+
 The algorithm passed in the I<cipher> parameter must support ASN1 encoding of
 its parameters.
 
@@ -30,21 +44,23 @@ L<CMS_add0_recipient_key(3)>.
 The B<CMS_ContentInfo> structure needs to be finalized using L<CMS_final(3)>
 and then freed using L<CMS_ContentInfo_free(3)>.
 
-CMS_EnvelopedData_create() is similar to CMS_EnvelopedData_create_with_libctx()
-but uses default values of NULL for the library context I<libctx> and the
-property query I<propq>.
+CMS_EnvelopedData_create() and  CMS_AuthEnvelopedData_create are similar to
+CMS_EnvelopedData_create_with_libctx() and
+CMS_AuthEnvelopedData_create_with_libctx() but use default values of NULL for
+the library context I<libctx> and the property query I<propq>.
 
 =head1 NOTES
 
-Although CMS_EnvelopedData_create() allocates a new B<CMS_ContentInfo>
-structure it is usually not used in applications. The wrappers
-L<CMS_encrypt(3)> and L<CMS_decrypt(3)> are often used instead.
+Although CMS_EnvelopedData_create() and CMS_AuthEnvelopedData_create() allocate
+a new B<CMS_ContentInfo> structure, they are not usually used in applications.
+The wrappers L<CMS_encrypt(3)> and L<CMS_decrypt(3)> are often used instead.
 
 =head1 RETURN VALUES
 
-If the allocation fails, CMS_EnvelopedData_create() returns NULL and sets
-an error code that can be obtained by L<ERR_get_error(3)>.
-Otherwise it returns a pointer to the newly allocated structure.
+If the allocation fails, CMS_EnvelopedData_create() and
+CMS_AuthEnvelopedData_create() return NULL and set an error code that can be
+obtained by L<ERR_get_error(3)>. Otherwise they return a pointer to the newly
+allocated structure.
 
 =head1 SEE ALSO
 
diff --git a/doc/man3/CMS_decrypt.pod b/doc/man3/CMS_decrypt.pod
index 3124fa8394..4f8d32fbbb 100644
--- a/doc/man3/CMS_decrypt.pod
+++ b/doc/man3/CMS_decrypt.pod
@@ -18,9 +18,9 @@ content from a CMS envelopedData structure
 =head1 DESCRIPTION
 
 CMS_decrypt() extracts and decrypts the content from a CMS EnvelopedData
-structure. B<pkey> is the private key of the recipient, B<cert> is the
-recipient's certificate, B<out> is a BIO to write the content to and
-B<flags> is an optional set of flags.
+or AuthEnvelopedData structure. B<pkey> is the private key of the recipient,
+B<cert> is the recipient's certificate, B<out> is a BIO to write the content to
+and B<flags> is an optional set of flags.
 
 The B<dcont> parameter is used in the rare case where the encrypted content
 is detached. It will normally be set to NULL.
diff --git a/doc/man3/CMS_encrypt.pod b/doc/man3/CMS_encrypt.pod
index 211ec18d36..9fe92e3ee6 100644
--- a/doc/man3/CMS_encrypt.pod
+++ b/doc/man3/CMS_encrypt.pod
@@ -11,17 +11,19 @@ CMS_encrypt_with_libctx, CMS_encrypt - create a CMS envelopedData structure
  CMS_ContentInfo *CMS_encrypt_with_libctx(STACK_OF(X509) *certs,
                                           BIO *in, const EVP_CIPHER *cipher,
                                           unsigned int flags,
-                                          OPENSSL_CTX *libctx, const char *propq);
+                                          OPENSSL_CTX *libctx,
+                                          const char *propq);
  CMS_ContentInfo *CMS_encrypt(STACK_OF(X509) *certs, BIO *in,
                               const EVP_CIPHER *cipher, unsigned int flags);
 
 =head1 DESCRIPTION
 
-CMS_encrypt_with_libctx() creates and returns a CMS EnvelopedData structure.
-I<certs> is a list of recipient certificates. I<in> is the content to be
-encrypted. I<cipher> is the symmetric cipher to use. I<flags> is an optional set
-of flags. The library context I<libctx> and the property query I<propq> are used
-internally when retrieving algorithms from providers.
+CMS_encrypt_with_libctx() creates and returns a CMS EnvelopedData or
+AuthEnvelopedData structure. I<certs> is a list of recipient certificates.
+I<in> is the content to be encrypted. I<cipher> is the symmetric cipher to use.
+I<flags> is an optional set of flags. The library context I<libctx> and the
+property query I<propq> are used internally when retrieving algorithms from
+providers.
 
 Only certificates carrying RSA, Diffie-Hellman or EC keys are supported by this
 function.
@@ -30,7 +32,9 @@ EVP_des_ede3_cbc() (triple DES) is the algorithm of choice for S/MIME use
 because most clients will support it.
 
 The algorithm passed in the B<cipher> parameter must support ASN1 encoding of
-its parameters.
+its parameters. If the cipher mode is GCM, then an AuthEnvelopedData structure
+containing MAC is used. Otherwise an EnvelopedData structure is used. Currently
+the AES variants with GCM mode are the only supported AEAD algorithms.
 
 Many browsers implement a "sign and encrypt" option which is simply an S/MIME
 envelopedData containing an S/MIME signed message. This can be readily produced
@@ -81,8 +85,8 @@ and CMS_add0_recipient_key().
 The parameter B<certs> may be NULL if B<CMS_PARTIAL> is set and recipients
 added later using CMS_add1_recipient_cert() or CMS_add0_recipient_key().
 
-CMS_encrypt() is similar to CMS_encrypt_with_libctx() but uses default values of
-NULL for the library context I<libctx> and the property query I<propq>.
+CMS_encrypt() is similar to CMS_encrypt_with_libctx() but uses default values
+of NULL for the library context I<libctx> and the property query I<propq>.
 
 =head1 RETURN VALUES
 
diff --git a/include/crypto/asn1.h b/include/crypto/asn1.h
index 624df3cb05..6e1d396851 100644
--- a/include/crypto/asn1.h
+++ b/include/crypto/asn1.h
@@ -7,6 +7,8 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <openssl/asn1.h>
+
 /* Internal ASN1 structures and functions: not for application use */
 
 /* ASN1 public key method structure */
@@ -124,3 +126,10 @@ struct asn1_pctx_st {
     unsigned long oid_flags;
     unsigned long str_flags;
 } /* ASN1_PCTX */ ;
+
+/* ASN1 type functions */
+
+int asn1_type_set_octetstring_int(ASN1_TYPE *a, long num,
+                                  unsigned char *data, int len);
+int asn1_type_get_octetstring_int(const ASN1_TYPE *a, long *num,
+                                  unsigned char *data, int max_len);
diff --git a/include/crypto/evp.h b/include/crypto/evp.h
index 7008e490e8..c488834511 100644
--- a/include/crypto/evp.h
+++ b/include/crypto/evp.h
@@ -511,6 +511,18 @@ const EVP_CIPHER *EVP_##cname##_ecb(void) { return &cname##_ecb; }
                              (fl)|EVP_CIPH_FLAG_DEFAULT_ASN1, \
                              cipher##_init_key, NULL, NULL, NULL, NULL)
 
+typedef struct {
+    unsigned char iv[EVP_MAX_IV_LENGTH];
+    unsigned int iv_len;
+    unsigned int tag_len;
+} evp_cipher_aead_asn1_params;
+
+int evp_cipher_param_to_asn1_ex(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
+                                evp_cipher_aead_asn1_params *params);
+
+int evp_cipher_asn1_to_param_ex(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
+                                evp_cipher_aead_asn1_params *params);
+
 /*
  * An EVP_PKEY can have the following states:
  *
diff --git a/include/openssl/asn1err.h b/include/openssl/asn1err.h
index f610d8816d..b58339ba47 100644
--- a/include/openssl/asn1err.h
+++ b/include/openssl/asn1err.h
@@ -82,6 +82,7 @@ int ERR_load_ASN1_strings(void);
 #  define ASN1_F_ASN1_TIME_ADJ                             0
 #  define ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING             0
 #  define ASN1_F_ASN1_TYPE_GET_OCTETSTRING                 0
+#  define ASN1_F_ASN1_TYPE_GET_OCTETSTRING_INT             0
 #  define ASN1_F_ASN1_UTCTIME_ADJ                          0
 #  define ASN1_F_ASN1_VERIFY                               0
 #  define ASN1_F_B64_READ_ASN1                             0
diff --git a/include/openssl/cms.h b/include/openssl/cms.h
index 7397008fcb..ad6718dd6f 100644
--- a/include/openssl/cms.h
+++ b/include/openssl/cms.h
@@ -189,6 +189,11 @@ int CMS_decrypt_set1_password(CMS_ContentInfo *cms,
 STACK_OF(CMS_RecipientInfo) *CMS_get0_RecipientInfos(CMS_ContentInfo *cms);
 int CMS_RecipientInfo_type(CMS_RecipientInfo *ri);
 EVP_PKEY_CTX *CMS_RecipientInfo_get0_pkey_ctx(CMS_RecipientInfo *ri);
+CMS_ContentInfo *CMS_AuthEnvelopedData_create(const EVP_CIPHER *cipher);
+CMS_ContentInfo *
+CMS_AuthEnvelopedData_create_with_libctx(const EVP_CIPHER *cipher,
+                                         OPENSSL_CTX *ctx,
+                                         const char *propq);
 CMS_ContentInfo *CMS_EnvelopedData_create(const EVP_CIPHER *cipher);
 CMS_ContentInfo *CMS_EnvelopedData_create_with_libctx(const EVP_CIPHER *cipher,
                                                       OPENSSL_CTX *ctx,
diff --git a/include/openssl/cmserr.h b/include/openssl/cmserr.h
index 97704bfa52..1e7daf044b 100644
--- a/include/openssl/cmserr.h
+++ b/include/openssl/cmserr.h
@@ -131,6 +131,8 @@ int ERR_load_CMS_strings(void);
 #  define CMS_R_CERTIFICATE_ALREADY_PRESENT                175
 #  define CMS_R_CERTIFICATE_HAS_NO_KEYID                   160
 #  define CMS_R_CERTIFICATE_VERIFY_ERROR                   100
+#  define CMS_R_CIPHER_AEAD_SET_TAG_ERROR                  184
+#  define CMS_R_CIPHER_GET_TAG                             185
 #  define CMS_R_CIPHER_INITIALISATION_ERROR                101
 #  define CMS_R_CIPHER_PARAMETER_INITIALISATION_ERROR      102
 #  define CMS_R_CMS_DATAFINAL_ERROR                        103
diff --git a/test/cmsapitest.c b/test/cmsapitest.c
index 697daa814d..f90200e9ac 100644
--- a/test/cmsapitest.c
+++ b/test/cmsapitest.c
@@ -21,7 +21,7 @@ DEFINE_STACK_OF(X509)
 static X509 *cert = NULL;
 static EVP_PKEY *privkey = NULL;
 
-static int test_encrypt_decrypt(void)
+static int test_encrypt_decrypt(const EVP_CIPHER *cipher)
 {
     int testresult = 0;
     STACK_OF(X509) *certstack = sk_X509_new_null();
@@ -37,7 +37,7 @@ static int test_encrypt_decrypt(void)
     if (!TEST_int_gt(sk_X509_push(certstack, cert), 0))
         goto end;
 
-    content = CMS_encrypt(certstack, msgbio, EVP_aes_128_cbc(), CMS_TEXT);
+    content = CMS_encrypt(certstack, msgbio, cipher, CMS_TEXT);
     if (!TEST_ptr(content))
         goto end;
 
@@ -60,6 +60,26 @@ static int test_encrypt_decrypt(void)
     return testresult;
 }
 
+static int test_encrypt_decrypt_aes_cbc(void)
+{
+    return test_encrypt_decrypt(EVP_aes_128_cbc());
+}
+
+static int test_encrypt_decrypt_aes_128_gcm(void)
+{
+    return test_encrypt_decrypt(EVP_aes_128_gcm());
+}
+
+static int test_encrypt_decrypt_aes_192_gcm(void)
+{
+    return test_encrypt_decrypt(EVP_aes_192_gcm());
+}
+
+static int test_encrypt_decrypt_aes_256_gcm(void)
+{
+    return test_encrypt_decrypt(EVP_aes_256_gcm());
+}
+
 OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n")
 
 int setup_tests(void)
@@ -99,7 +119,10 @@ int setup_tests(void)
     }
     BIO_free(privkeybio);
 
-    ADD_TEST(test_encrypt_decrypt);
+    ADD_TEST(test_encrypt_decrypt_aes_cbc);
+    ADD_TEST(test_encrypt_decrypt_aes_128_gcm);
+    ADD_TEST(test_encrypt_decrypt_aes_192_gcm);
+    ADD_TEST(test_encrypt_decrypt_aes_256_gcm);
 
     return 1;
 }
diff --git a/test/drbgtest.c b/test/drbgtest.c
index eeb71f0227..d069460cd5 100644
--- a/test/drbgtest.c
+++ b/test/drbgtest.c
@@ -23,6 +23,7 @@
 #include <openssl/aes.h>
 #include "../crypto/rand/rand_local.h"
 #include "../include/crypto/rand.h"
+#include "../include/crypto/evp.h"
 #include "../providers/implementations/rands/drbg_local.h"
 #include "../crypto/evp/evp_local.h"
 
diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t
index 1edddb2a82..65a8e14574 100644
--- a/test/recipes/80-test_cms.t
+++ b/test/recipes/80-test_cms.t
@@ -298,7 +298,7 @@ my @smime_cms_tests = (
       \&final_compare
     ],
 
-    [ "enveloped content test streaming PEM format, KEK",
+    [ "enveloped content test streaming PEM format, AES-256-CBC cipher, KEK",
       [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, "-outform", "PEM", "-aes128",
         "-stream", "-out", "{output}.cms",
         "-secretkey", "000102030405060708090A0B0C0D0E0F",
@@ -310,6 +310,18 @@ my @smime_cms_tests = (
       \&final_compare
     ],
 
+    [ "enveloped content test streaming PEM format, AES-256-GCM cipher, KEK",
+      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, "-outform", "PEM", "-aes-128-gcm",
+        "-stream", "-out", "{output}.cms",
+        "-secretkey", "000102030405060708090A0B0C0D0E0F",
+        "-secretkeyid", "C0FEE0" ],
+      [ "{cmd2}", "-decrypt", "-in", "{output}.cms", "-out", "{output}.txt",
+        "-inform", "PEM",
+        "-secretkey", "000102030405060708090A0B0C0D0E0F",
+        "-secretkeyid", "C0FEE0" ],
+      \&final_compare
+    ],
+
     [ "enveloped content test streaming PEM format, KEK, key only",
       [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, "-outform", "PEM", "-aes128",
         "-stream", "-out", "{output}.cms",
@@ -373,7 +385,6 @@ my @smime_cms_tests = (
         "-out", "{output}.txt" ],
       \&final_compare
     ],
-
 );
 
 my @smime_cms_cades_tests = (
@@ -560,7 +571,7 @@ my @smime_cms_param_tests = (
       \&final_compare
     ],
 
-    [ "enveloped content test streaming S/MIME format, ECDH, AES128, SHA256 KDF",
+    [ "enveloped content test streaming S/MIME format, ECDH, AES-128-CBC, SHA256 KDF",
       [ "{cmd1}", @prov, "-encrypt", "-in", $smcont,
         "-stream", "-out", "{output}.cms",
         "-recip", catfile($smdir, "smec1.pem"), "-aes128",
@@ -570,6 +581,15 @@ my @smime_cms_param_tests = (
       \&final_compare
     ],
 
+    [ "enveloped content test streaming S/MIME format, ECDH, AES-128-GCM cipher, SHA256 KDF",
+      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont,
+        "-stream", "-out", "{output}.cms",
+        "-recip", catfile($smdir, "smec1.pem"), "-aes-128-gcm", "-keyopt", "ecdh_kdf_md:sha256" ],
+      [ "{cmd2}", "-decrypt", "-recip", catfile($smdir, "smec1.pem"),
+	      "-in", "{output}.cms", "-out", "{output}.txt" ],
+      \&final_compare
+    ],
+
     [ "enveloped content test streaming S/MIME format, ECDH, K-283, cofactor DH",
       [ "{cmd1}", @prov, "-encrypt", "-in", $smcont,
         "-stream", "-out", "{output}.cms",
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 4982a7f93c..777d8ce8a8 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -5299,3 +5299,5 @@ ossl_b2i_bio                            ?	3_0_0	EXIST::FUNCTION:DSA
 EVP_PKEY_CTX_set1_id                    ?	3_0_0	EXIST::FUNCTION:
 EVP_PKEY_CTX_get1_id                    ?	3_0_0	EXIST::FUNCTION:
 EVP_PKEY_CTX_get1_id_len                ?	3_0_0	EXIST::FUNCTION:
+CMS_AuthEnvelopedData_create            ?	3_0_0	EXIST::FUNCTION:CMS
+CMS_AuthEnvelopedData_create_with_libctx ?	3_0_0	EXIST::FUNCTION:CMS


More information about the openssl-commits mailing list