mirror of
https://github.com/openssl/openssl.git
synced 2025-02-17 14:32:04 +08:00
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:
parent
d96486dc80
commit
924663c36d
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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) */
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
/*
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user