summaryrefslogtreecommitdiffstats
path: root/crypto/cms
diff options
context:
space:
mode:
authorJakub Zelenka <jakub.openssl@gmail.com>2020-09-06 19:11:34 +0100
committerTomas Mraz <tmraz@fedoraproject.org>2020-09-08 15:43:11 +0200
commit924663c36d47066d5307937da77fed7e872730c7 (patch)
treea60cfe385cc29402bdaceaaa5a8b069ca6a6a50a /crypto/cms
parentd96486dc809b5d134055785bfa6d707195d95534 (diff)
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@oracle.com> Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org> (Merged from https://github.com/openssl/openssl/pull/8024)
Diffstat (limited to 'crypto/cms')
-rw-r--r--crypto/cms/cms_asn1.c12
-rw-r--r--crypto/cms/cms_enc.c32
-rw-r--r--crypto/cms/cms_env.c345
-rw-r--r--crypto/cms/cms_err.c3
-rw-r--r--crypto/cms/cms_kari.c4
-rw-r--r--crypto/cms/cms_lib.c24
-rw-r--r--crypto/cms/cms_local.h21
-rw-r--r--crypto/cms/cms_pwri.c16
-rw-r--r--crypto/cms/cms_smime.c20
9 files changed, 379 insertions, 98 deletions
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