/* * SecCmsEnvelopedDataCreate - create an enveloped data message */ SecCmsEnvelopedData * SecCmsEnvelopedDataCreate(SecCmsMessage *cmsg, SECOidTag algorithm, int keysize) { void *mark; SecCmsEnvelopedData *envd; PLArenaPool *poolp; OSStatus rv; poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); envd = (SecCmsEnvelopedData *)PORT_ArenaZAlloc(poolp, sizeof(SecCmsEnvelopedData)); if (envd == NULL) goto loser; envd->cmsg = cmsg; /* version is set in SecCmsEnvelopedDataEncodeBeforeStart() */ rv = SecCmsContentInfoSetContentEncAlg(poolp, &(envd->contentInfo), algorithm, NULL, keysize); if (rv != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return envd; loser: PORT_ArenaRelease(poolp, mark); return NULL; }
/* * SecCmsEncryptedDataCreate - create an empty encryptedData object. * * "algorithm" specifies the bulk encryption algorithm to use. * "keysize" is the key size. * * An error results in a return value of NULL and an error set. * (Retrieve specific errors via PORT_GetError()/XP_GetError().) */ SecCmsEncryptedDataRef SecCmsEncryptedDataCreate(SecCmsMessageRef cmsg, SECOidTag algorithm, int keysize) { void *mark; SecCmsEncryptedDataRef encd; PLArenaPool *poolp; #if 0 SECAlgorithmID *pbe_algid; #endif OSStatus rv; poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); encd = (SecCmsEncryptedDataRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsEncryptedData)); if (encd == NULL) goto loser; encd->cmsg = cmsg; /* version is set in SecCmsEncryptedDataEncodeBeforeStart() */ switch (algorithm) { /* XXX hmmm... hardcoded algorithms? */ 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: /* Assume password-based-encryption. At least, try that. */ #if 1 // @@@ Fix me rv = SECFailure; break; #else pbe_algid = PK11_CreatePBEAlgorithmID(algorithm, 1, NULL); if (pbe_algid == NULL) { rv = SECFailure; break; } rv = SecCmsContentInfoSetContentEncAlgID((SecArenaPoolRef)poolp, &(encd->contentInfo), pbe_algid, keysize); SECOID_DestroyAlgorithmID (pbe_algid, PR_TRUE); break; #endif } if (rv != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return encd; loser: PORT_ArenaRelease(poolp, mark); return NULL; }
/* * SecCmsEnvelopedDataEncodeBeforeStart - prepare this envelopedData for encoding * * at this point, we need * - recipientinfos set up with recipient's certificates * - a content encryption algorithm (if none, 3DES will be used) * * this function will generate a random content encryption key (aka bulk key), * initialize the recipientinfos with certificate identification and wrap the bulk key * using the proper algorithm for every certificiate. * it will finally set the bulk algorithm and key so that the encode step can find it. */ OSStatus SecCmsEnvelopedDataEncodeBeforeStart(SecCmsEnvelopedData *envd) { int version; SecCmsRecipientInfo **recipientinfos; SecCmsContentInfo *cinfo; SecSymmetricKeyRef bulkkey = NULL; CSSM_ALGORITHMS algorithm; SECOidTag bulkalgtag; //CK_MECHANISM_TYPE type; //PK11SlotInfo *slot; OSStatus rv; CSSM_DATA *dummy; PLArenaPool *poolp; extern const SEC_ASN1Template SecCmsRecipientInfoTemplate[]; void *mark = NULL; int i; poolp = envd->cmsg->poolp; cinfo = &(envd->contentInfo); recipientinfos = envd->recipientInfos; if (recipientinfos == NULL) { PORT_SetError(SEC_ERROR_BAD_DATA); #if 0 PORT_SetErrorString("Cannot find recipientinfos to encode."); #endif goto loser; } version = SEC_CMS_ENVELOPED_DATA_VERSION_REG; if (envd->originatorInfo != NULL || envd->unprotectedAttr != NULL) { version = SEC_CMS_ENVELOPED_DATA_VERSION_ADV; } else { for (i = 0; recipientinfos[i] != NULL; i++) { if (SecCmsRecipientInfoGetVersion(recipientinfos[i]) != 0) { version = SEC_CMS_ENVELOPED_DATA_VERSION_ADV; break; } } } dummy = SEC_ASN1EncodeInteger(poolp, &(envd->version), version); if (dummy == NULL) goto loser; /* now we need to have a proper content encryption algorithm * on the SMIME level, we would figure one out by looking at SMIME capabilities * we cannot do that on our level, so if none is set already, we'll just go * with one of the mandatory algorithms (3DES) */ if ((bulkalgtag = SecCmsContentInfoGetContentEncAlgTag(cinfo)) == SEC_OID_UNKNOWN) { rv = SecCmsContentInfoSetContentEncAlg(poolp, cinfo, SEC_OID_DES_EDE3_CBC, NULL, 168); if (rv != SECSuccess) goto loser; bulkalgtag = SEC_OID_DES_EDE3_CBC; } algorithm = SECOID_FindyCssmAlgorithmByTag(bulkalgtag); if (!algorithm) goto loser; rv = SecKeyGenerate(NULL, /* keychainRef */ algorithm, SecCmsContentInfoGetBulkKeySize(cinfo), 0, /* contextHandle */ CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT, CSSM_KEYATTR_EXTRACTABLE, NULL, /* initialAccess */ &bulkkey); if (rv) goto loser; mark = PORT_ArenaMark(poolp); /* Encrypt the bulk key with the public key of each recipient. */ for (i = 0; recipientinfos[i] != NULL; i++) { rv = SecCmsRecipientInfoWrapBulkKey(recipientinfos[i], bulkkey, bulkalgtag); if (rv != SECSuccess) goto loser; /* error has been set by SecCmsRecipientInfoEncryptBulkKey */ /* could be: alg not supported etc. */ } /* the recipientinfos are all finished. now sort them by DER for SET OF encoding */ rv = SecCmsArraySortByDER((void **)envd->recipientInfos, SecCmsRecipientInfoTemplate, NULL); if (rv != SECSuccess) goto loser; /* error has been set by SecCmsArraySortByDER */ /* store the bulk key in the contentInfo so that the encoder can find it */ SecCmsContentInfoSetBulkKey(cinfo, bulkkey); PORT_ArenaUnmark(poolp, mark); CFRelease(bulkkey); return SECSuccess; loser: if (mark != NULL) PORT_ArenaRelease (poolp, mark); if (bulkkey) CFRelease(bulkkey); return SECFailure; }