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)
This commit is contained in:
Jakub Zelenka 2020-09-06 19:11:34 +01:00 committed by Tomas Mraz
parent d96486dc80
commit 924663c36d
26 changed files with 686 additions and 180 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);
CMS_ContentInfo *cms;
CMS_AuthEnvelopedData *aenv;
env = cms_get0_enveloped(cms);
if (env == NULL)
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 (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();
if (cms->d.envelopedData->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;
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

View File

@ -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),

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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))

View File

@ -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

View File

@ -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) */

View File

@ -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 */
/*

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -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:
*

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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"

View File

@ -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",

View File

@ -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