The branch master has been updated via 924663c36d47066d5307937da77fed7e872730c7 (commit) from d96486dc809b5d134055785bfa6d707195d95534 (commit)
- Log ----------------------------------------------------------------- commit 924663c36d47066d5307937da77fed7e872730c7 Author: Jakub Zelenka <jakub.open...@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.lon...@oracle.com> Reviewed-by: Tomas Mraz <tm...@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