OSStatus SecCmsSignedDataAddDigest(SecArenaPoolRef pool, SecCmsSignedDataRef sigd, SECOidTag digestalgtag, CSSM_DATA_PTR digest) { PRArenaPool *poolp = (PRArenaPool *)pool; SECAlgorithmID *digestalg; void *mark; mark = PORT_ArenaMark(poolp); digestalg = PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID)); if (digestalg == NULL) goto loser; if (SECOID_SetAlgorithmID (poolp, digestalg, digestalgtag, NULL) != SECSuccess) /* no params */ goto loser; if (SecCmsArrayAdd(poolp, (void ***)&(sigd->digestAlgorithms), (void *)digestalg) != SECSuccess || /* even if digest is NULL, add dummy to have same-size array */ SecCmsArrayAdd(poolp, (void ***)&(sigd->digests), (void *)digest) != SECSuccess) { goto loser; } PORT_ArenaUnmark(poolp, mark); return SECSuccess; loser: PORT_ArenaRelease(poolp, mark); return SECFailure; }
/* * SecCmsAttributeArraySetAttr - set an attribute's value in a set of attributes */ OSStatus SecCmsAttributeArraySetAttr(PLArenaPool *poolp, SecCmsAttribute ***attrs, SECOidTag type, CSSM_DATA_PTR value, Boolean encoded) { SecCmsAttribute *attr; void *mark; mark = PORT_ArenaMark(poolp); /* see if we have one already */ attr = SecCmsAttributeArrayFindAttrByOidTag(*attrs, type, PR_FALSE); if (attr == NULL) { /* not found? create one! */ attr = SecCmsAttributeCreate(poolp, type, value, encoded); if (attr == NULL) goto loser; /* and add it to the list */ if (SecCmsArrayAdd(poolp, (void ***)attrs, (void *)attr) != SECSuccess) goto loser; } else { /* found, shove it in */ /* XXX we need a decent memory model @#$#$!#!!! */ attr->values[0] = value; attr->encoded = encoded; } PORT_ArenaUnmark (poolp, mark); return SECSuccess; loser: PORT_ArenaRelease (poolp, mark); return SECFailure; }
/* * SecCmsAttributeArrayAddAttr - add an attribute to an * array of attributes. */ OSStatus SecCmsAttributeArrayAddAttr(PLArenaPool *poolp, SecCmsAttribute ***attrs, SecCmsAttribute *attr) { SecCmsAttribute *oattr; void *mark; SECOidTag type; mark = PORT_ArenaMark(poolp); /* find oidtag of attr */ type = SecCmsAttributeGetType(attr); /* see if we have one already */ oattr = SecCmsAttributeArrayFindAttrByOidTag(*attrs, type, PR_FALSE); PORT_Assert (oattr == NULL); if (oattr != NULL) goto loser; /* XXX or would it be better to replace it? */ /* no, shove it in */ if (SecCmsArrayAdd(poolp, (void ***)attrs, (void *)attr) != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return SECSuccess; loser: PORT_ArenaRelease(poolp, mark); return SECFailure; }
/* * SecCmsAttributeAddValue - add another value to an attribute */ OSStatus SecCmsAttributeAddValue(PLArenaPool *poolp, SecCmsAttribute *attr, CSSM_DATA_PTR value) { CSSM_DATA copiedvalue; void *mark; PORT_Assert (poolp != NULL); mark = PORT_ArenaMark(poolp); /* XXX we need an object memory model #$%#$%! */ if (SECITEM_CopyItem(poolp, &copiedvalue, value) != SECSuccess) goto loser; if (SecCmsArrayAdd(poolp, (void ***)&(attr->values), (void *)&copiedvalue) != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return SECSuccess; loser: PORT_Assert (mark != NULL); PORT_ArenaRelease (poolp, mark); return SECFailure; }
/* * SecCmsAttributeCreate - create an attribute * * if value is NULL, the attribute won't have a value. It can be added later * with SecCmsAttributeAddValue. */ SecCmsAttribute * SecCmsAttributeCreate(PRArenaPool *poolp, SECOidTag oidtag, CSSM_DATA_PTR value, Boolean encoded) { SecCmsAttribute *attr; CSSM_DATA_PTR copiedvalue; void *mark; PORT_Assert (poolp != NULL); mark = PORT_ArenaMark (poolp); attr = (SecCmsAttribute *)PORT_ArenaZAlloc(poolp, sizeof(SecCmsAttribute)); if (attr == NULL) goto loser; attr->typeTag = SECOID_FindOIDByTag(oidtag); if (attr->typeTag == NULL) goto loser; if (SECITEM_CopyItem(poolp, &(attr->type), &(attr->typeTag->oid)) != SECSuccess) goto loser; if (value != NULL) { if ((copiedvalue = SECITEM_AllocItem(poolp, NULL, (unsigned int)value->Length)) == NULL) goto loser; if (SECITEM_CopyItem(poolp, copiedvalue, value) != SECSuccess) goto loser; SecCmsArrayAdd(poolp, (void ***)&(attr->values), (void *)copiedvalue); } attr->encoded = encoded; PORT_ArenaUnmark (poolp, mark); return attr; loser: PORT_Assert (mark != NULL); PORT_ArenaRelease (poolp, mark); return NULL; }
OSStatus SecCmsSignedDataAddSignerInfo(SecCmsSignedDataRef sigd, SecCmsSignerInfoRef signerinfo) { void *mark; OSStatus rv; SECOidTag digestalgtag; PLArenaPool *poolp; poolp = sigd->cmsg->poolp; mark = PORT_ArenaMark(poolp); /* add signerinfo */ rv = SecCmsArrayAdd(poolp, (void ***)&(sigd->signerInfos), (void *)signerinfo); if (rv != SECSuccess) goto loser; signerinfo->sigd = sigd; /* * add empty digest * Empty because we don't have it yet. Either it gets created during encoding * (if the data is present) or has to be set externally. * XXX maybe pass it in optionally? */ digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo); rv = SecCmsSignedDataSetDigestValue(sigd, digestalgtag, NULL); if (rv != SECSuccess) goto loser; /* * The last thing to get consistency would be adding the digest. */ PORT_ArenaUnmark(poolp, mark); return SECSuccess; loser: PORT_ArenaRelease (poolp, mark); return SECFailure; }
/* * SecCmsEnvelopedDataAddRecipient - add a recipientinfo to the enveloped data msg * * rip must be created on the same pool as edp - this is not enforced, though. */ OSStatus SecCmsEnvelopedDataAddRecipient(SecCmsEnvelopedData *edp, SecCmsRecipientInfo *rip) { void *mark; OSStatus rv; /* XXX compare pools, if not same, copy rip into edp's pool */ PR_ASSERT(edp != NULL); PR_ASSERT(rip != NULL); mark = PORT_ArenaMark(edp->cmsg->poolp); rv = SecCmsArrayAdd(edp->cmsg->poolp, (void ***)&(edp->recipientInfos), (void *)rip); if (rv != SECSuccess) { PORT_ArenaRelease(edp->cmsg->poolp, mark); return SECFailure; } PORT_ArenaUnmark (edp->cmsg->poolp, mark); return SECSuccess; }
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; }