#include <Security/SecCmsEncryptedData.h>
#include <Security/SecCmsContentInfo.h>
#include "cmslocal.h"
#include "secitem.h"
#include "secoid.h"
#include <security_asn1/secasn1.h>
#include <security_asn1/secerr.h>
SecCmsEncryptedDataRef
SecCmsEncryptedDataCreate(SecCmsMessageRef cmsg, SECOidTag algorithm, int keysize)
{
void *mark;
SecCmsEncryptedDataRef encd;
PLArenaPool *poolp;
SECAlgorithmID *pbe_algid;
OSStatus rv;
poolp = cmsg->poolp;
mark = PORT_ArenaMark(poolp);
encd = (SecCmsEncryptedDataRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsEncryptedData));
if (encd == NULL)
goto loser;
encd->cmsg = cmsg;
switch (algorithm) {
case SEC_OID_RC2_CBC:
case SEC_OID_DES_EDE3_CBC:
case SEC_OID_DES_CBC:
rv = SecCmsContentInfoSetContentEncAlg((SecArenaPoolRef)poolp, &(encd->contentInfo), algorithm, NULL, keysize);
break;
default:
#if 1
pbe_algid = NULL;
#else
pbe_algid = PK11_CreatePBEAlgorithmID(algorithm, 1, NULL);
#endif
if (pbe_algid == NULL) {
rv = SECFailure;
break;
}
rv = SecCmsContentInfoSetContentEncAlgID((SecArenaPoolRef)poolp, &(encd->contentInfo), pbe_algid, keysize);
SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE);
break;
}
if (rv != SECSuccess)
goto loser;
PORT_ArenaUnmark(poolp, mark);
return encd;
loser:
PORT_ArenaRelease(poolp, mark);
return NULL;
}
void
SecCmsEncryptedDataDestroy(SecCmsEncryptedDataRef encd)
{
if (encd == NULL) {
return;
}
SecCmsContentInfoDestroy(&(encd->contentInfo));
return;
}
SecCmsContentInfoRef
SecCmsEncryptedDataGetContentInfo(SecCmsEncryptedDataRef encd)
{
return &(encd->contentInfo);
}
OSStatus
SecCmsEncryptedDataEncodeBeforeStart(SecCmsEncryptedDataRef encd)
{
int version;
SecSymmetricKeyRef bulkkey = NULL;
CSSM_DATA_PTR dummy;
SecCmsContentInfoRef cinfo = &(encd->contentInfo);
if (SecCmsArrayIsEmpty((void **)encd->unprotectedAttr))
version = SEC_CMS_ENCRYPTED_DATA_VERSION;
else
version = SEC_CMS_ENCRYPTED_DATA_VERSION_UPATTR;
dummy = SEC_ASN1EncodeInteger (encd->cmsg->poolp, &(encd->version), version);
if (dummy == NULL)
return SECFailure;
if (encd->cmsg->decrypt_key_cb)
bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg,
SecCmsContentInfoGetContentEncAlg(cinfo));
if (bulkkey == NULL)
return SECFailure;
SecCmsContentInfoSetBulkKey(cinfo, bulkkey);
CFRelease(bulkkey);
return SECSuccess;
}
OSStatus
SecCmsEncryptedDataEncodeBeforeData(SecCmsEncryptedDataRef encd)
{
SecCmsContentInfoRef cinfo;
SecSymmetricKeyRef bulkkey;
SECAlgorithmID *algid;
cinfo = &(encd->contentInfo);
bulkkey = SecCmsContentInfoGetBulkKey(cinfo);
if (bulkkey == NULL)
return SECFailure;
algid = SecCmsContentInfoGetContentEncAlg(cinfo);
if (algid == NULL)
return SECFailure;
cinfo->ciphcx = SecCmsCipherContextStartEncrypt(encd->cmsg->poolp, bulkkey, algid);
CFRelease(bulkkey);
if (cinfo->ciphcx == NULL)
return SECFailure;
return SECSuccess;
}
OSStatus
SecCmsEncryptedDataEncodeAfterData(SecCmsEncryptedDataRef encd)
{
if (encd->contentInfo.ciphcx) {
SecCmsCipherContextDestroy(encd->contentInfo.ciphcx);
encd->contentInfo.ciphcx = NULL;
}
return SECSuccess;
}
OSStatus
SecCmsEncryptedDataDecodeBeforeData(SecCmsEncryptedDataRef encd)
{
SecSymmetricKeyRef bulkkey = NULL;
SecCmsContentInfoRef cinfo;
SECAlgorithmID *bulkalg;
OSStatus rv = SECFailure;
cinfo = &(encd->contentInfo);
bulkalg = SecCmsContentInfoGetContentEncAlg(cinfo);
if (encd->cmsg->decrypt_key_cb == NULL)
goto loser;
bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, bulkalg);
if (bulkkey == NULL)
goto loser;
SecCmsContentInfoSetBulkKey(cinfo, bulkkey);
cinfo->ciphcx = SecCmsCipherContextStartDecrypt(bulkkey, bulkalg);
if (cinfo->ciphcx == NULL)
goto loser;
#if 1
#else
if (SEC_PKCS5IsAlgorithmPBEAlg(bulkalg)) {
SEC_PKCS5KeyAndPassword *keyPwd = (SEC_PKCS5KeyAndPassword *)bulkkey;
bulkkey = keyPwd->key;
}
#endif
CFRelease(bulkkey);
rv = SECSuccess;
loser:
return rv;
}
OSStatus
SecCmsEncryptedDataDecodeAfterData(SecCmsEncryptedDataRef encd)
{
if (encd->contentInfo.ciphcx) {
SecCmsCipherContextDestroy(encd->contentInfo.ciphcx);
encd->contentInfo.ciphcx = NULL;
}
return SECSuccess;
}
OSStatus
SecCmsEncryptedDataDecodeAfterEnd(SecCmsEncryptedDataRef encd)
{
return SECSuccess;
}