static SecCmsRecipientInfoRef nss_cmsrecipientinfo_create(SecCmsEnvelopedDataRef envd, SecCmsRecipientIDSelector type, SecCertificateRef cert, SecPublicKeyRef pubKey, const SecAsn1Item *subjKeyID) { SecCmsRecipientInfoRef ri; void *mark; SECOidTag certalgtag; OSStatus rv = SECSuccess; SecCmsRecipientEncryptedKey *rek; SecCmsOriginatorIdentifierOrKey *oiok; unsigned long version; SecAsn1Item * dummy; PLArenaPool *poolp; const SECAlgorithmID *algid; SECAlgorithmID freeAlgID; SecCmsRecipientIdentifier *rid; poolp = envd->contentInfo.cmsg->poolp; mark = PORT_ArenaMark(poolp); ri = (SecCmsRecipientInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsRecipientInfo)); if (ri == NULL) goto loser; ri->envelopedData = envd; #if USE_CDSA_CRYPTO if (type == SecCmsRecipientIDIssuerSN) { rv = SecCertificateGetAlgorithmID(cert,&algid); } else { PORT_Assert(pubKey); rv = SecKeyGetAlgorithmID(pubKey,&algid); } #else ri->cert = CERT_DupCertificate(cert); if (ri->cert == NULL) goto loser; const SecAsn1AlgId *length_data_swapped = (const SecAsn1AlgId *)SecCertificateGetPublicKeyAlgorithm(cert); freeAlgID.algorithm.Length = (size_t)length_data_swapped->algorithm.Data; freeAlgID.algorithm.Data = (uint8_t *)length_data_swapped->algorithm.Length; freeAlgID.parameters.Length = (size_t)length_data_swapped->parameters.Data; freeAlgID.parameters.Data = (uint8_t *)length_data_swapped->parameters.Length; algid = &freeAlgID; #endif certalgtag = SECOID_GetAlgorithmTag(algid); rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: ri->recipientInfoType = SecCmsRecipientInfoIDKeyTrans; rid->identifierType = type; if (type == SecCmsRecipientIDIssuerSN) { rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); if (rid->id.issuerAndSN == NULL) { break; } } else if (type == SecCmsRecipientIDSubjectKeyID){ rid->id.subjectKeyID = PORT_ArenaNew(poolp, SecAsn1Item); if (rid->id.subjectKeyID == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID); if (rid->id.subjectKeyID->Data == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } #if 0 SecCmsKeyTransRecipientInfoEx *riExtra; riExtra = &ri->ri.keyTransRecipientInfoEx; riExtra->version = 0; riExtra->pubKey = SECKEY_CopyPublicKey(pubKey); if (riExtra->pubKey == NULL) { rv = SECFailure; PORT_SetError(SEC_ERROR_NO_MEMORY); break; } #endif } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } break; case SEC_OID_MISSI_KEA_DSS_OLD: case SEC_OID_MISSI_KEA_DSS: case SEC_OID_MISSI_KEA: PORT_Assert(type != SecCmsRecipientIDSubjectKeyID); if (type == SecCmsRecipientIDSubjectKeyID) { rv = SECFailure; break; } /* backward compatibility - this is not really a keytrans operation */ ri->recipientInfoType = SecCmsRecipientInfoIDKeyTrans; /* hardcoded issuerSN choice for now */ ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType = SecCmsRecipientIDIssuerSN; ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { rv = SECFailure; break; } break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ PORT_Assert(type != SecCmsRecipientIDSubjectKeyID); if (type == SecCmsRecipientIDSubjectKeyID) { rv = SECFailure; break; } /* a key agreement op */ ri->recipientInfoType = SecCmsRecipientInfoIDKeyAgree; if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { rv = SECFailure; break; } /* we do not support the case where multiple recipients * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys * in this case, we would need to walk all the recipientInfos, take the * ones that do KeyAgreement algorithms and join them, algorithm by algorithm * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */ /* only epheremal-static Diffie-Hellman is supported for now * this is the only form of key agreement that provides potential anonymity * of the sender, plus we do not have to include certs in the message */ /* force single recipientEncryptedKey for now */ if ((rek = SecCmsRecipientEncryptedKeyCreate(poolp)) == NULL) { rv = SECFailure; break; } /* hardcoded IssuerSN choice for now */ rek->recipientIdentifier.identifierType = SecCmsKeyAgreeRecipientIDIssuerSN; if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) { rv = SECFailure; break; } oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); /* see RFC2630 12.3.1.1 */ oiok->identifierType = SecCmsOriginatorIDOrKeyOriginatorPublicKey; rv = SecCmsArrayAdd(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys, (void *)rek); break; default: /* other algorithms not supported yet */ /* NOTE that we do not support any KEK algorithm */ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); rv = SECFailure; break; } if (rv == SECFailure) goto loser; /* set version */ switch (ri->recipientInfoType) { case SecCmsRecipientInfoIDKeyTrans: if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == SecCmsRecipientIDIssuerSN) version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN; else version = SEC_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY; dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version); if (dummy == NULL) goto loser; break; case SecCmsRecipientInfoIDKeyAgree: dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version), SEC_CMS_KEYAGREE_RECIPIENT_INFO_VERSION); if (dummy == NULL) goto loser; break; case SecCmsRecipientInfoIDKEK: /* NOTE: this cannot happen as long as we do not support any KEK algorithm */ dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version), SEC_CMS_KEK_RECIPIENT_INFO_VERSION); if (dummy == NULL) goto loser; break; } if (SecCmsEnvelopedDataAddRecipient(envd, ri)) goto loser; PORT_ArenaUnmark (poolp, mark); #if 0 if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); #endif return ri; loser: #if 0 if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); #endif PORT_ArenaRelease (poolp, mark); return NULL; }
/* * Set up a SecCmsMessageRef for a EnvelopedData creation. */ static OSStatus cmsSetupForEnvelopedData( CMSEncoderRef cmsEncoder) { ASSERT(cmsEncoder->op == EO_Encrypt); ASSERT(cmsEncoder->recipients != NULL); SecCmsContentInfoRef contentInfo = NULL; SecCmsEnvelopedDataRef envelopedData = NULL; SECOidTag algorithmTag; int keySize; OSStatus ortn; /* * Find encryption algorithm...unfortunately we need a NULL-terminated array * of SecCertificateRefs for this. */ CFIndex numCerts = CFArrayGetCount(cmsEncoder->recipients); CFIndex dex; SecCertificateRef *certArray = (SecCertificateRef *)malloc( (numCerts+1) * sizeof(SecCertificateRef)); for(dex=0; dex<numCerts; dex++) { certArray[dex] = (SecCertificateRef)CFArrayGetValueAtIndex( cmsEncoder->recipients, dex); } certArray[numCerts] = NULL; ortn = SecSMIMEFindBulkAlgForRecipients(certArray, &algorithmTag, &keySize); free(certArray); if(ortn) { CSSM_PERROR("SecSMIMEFindBulkAlgForRecipients", ortn); return ortn; } /* build chain of objects: message->envelopedData->data */ if(cmsEncoder->cmsMsg != NULL) { SecCmsMessageDestroy(cmsEncoder->cmsMsg); } cmsEncoder->cmsMsg = SecCmsMessageCreate(NULL); if(cmsEncoder->cmsMsg == NULL) { return errSecInternalComponent; } envelopedData = SecCmsEnvelopedDataCreate(cmsEncoder->cmsMsg, algorithmTag, keySize); if(envelopedData == NULL) { return errSecInternalComponent; } contentInfo = SecCmsMessageGetContentInfo(cmsEncoder->cmsMsg); ortn = SecCmsContentInfoSetContentEnvelopedData(cmsEncoder->cmsMsg, contentInfo, envelopedData); if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsContentInfoSetContentEnvelopedData", ortn); return ortn; } contentInfo = SecCmsEnvelopedDataGetContentInfo(envelopedData); if(cmsEncoder->eContentType.Data != NULL) { /* Override the default ContentType of id-data */ ortn = SecCmsContentInfoSetContentOther(cmsEncoder->cmsMsg, contentInfo, NULL, /* data - provided to encoder, not here */ FALSE, /* detachedContent */ &cmsEncoder->eContentType); } else { ortn = SecCmsContentInfoSetContentData(cmsEncoder->cmsMsg, contentInfo, NULL /* data - provided to encoder, not here */, cmsEncoder->detachedContent); } if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsContentInfoSetContentData*", ortn); return ortn; } /* * create & attach recipient information, one for each recipient */ for(dex=0; dex<numCerts; dex++) { SecCmsRecipientInfoRef recipientInfo = NULL; SecCertificateRef thisRecip = (SecCertificateRef)CFArrayGetValueAtIndex( cmsEncoder->recipients, dex); recipientInfo = SecCmsRecipientInfoCreate(cmsEncoder->cmsMsg, thisRecip); ortn = SecCmsEnvelopedDataAddRecipient(envelopedData, recipientInfo); if(ortn) { ortn = cmsRtnToOSStatus(ortn); CSSM_PERROR("SecCmsEnvelopedDataAddRecipient", ortn); return ortn; } } return errSecSuccess; }