/* * NSS_CMSAttributeArray_SetAttr - set an attribute's value in a set of attributes */ SECStatus NSS_CMSAttributeArray_SetAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, SECOidTag type, SECItem *value, PRBool encoded) { NSSCMSAttribute *attr; void *mark; mark = PORT_ArenaMark(poolp); /* see if we have one already */ attr = NSS_CMSAttributeArray_FindAttrByOidTag(*attrs, type, PR_FALSE); if (attr == NULL) { /* not found? create one! */ attr = NSS_CMSAttribute_Create(poolp, type, value, encoded); if (attr == NULL) goto loser; /* and add it to the list */ if (NSS_CMSArray_Add(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; }
/* * NSS_CMSAttributeArray_AddAttr - add an attribute to an * array of attributes. */ SECStatus NSS_CMSAttributeArray_AddAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, NSSCMSAttribute *attr) { NSSCMSAttribute *oattr; void *mark; SECOidTag type; mark = PORT_ArenaMark(poolp); /* find oidtag of attr */ type = NSS_CMSAttribute_GetType(attr); /* see if we have one already */ oattr = NSS_CMSAttributeArray_FindAttrByOidTag(*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 (NSS_CMSArray_Add(poolp, (void ***)attrs, (void *)attr) != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return SECSuccess; loser: PORT_ArenaRelease(poolp, mark); return SECFailure; }
/* * NSS_CMSAttribute_AddValue - add another value to an attribute */ SECStatus NSS_CMSAttribute_AddValue(PLArenaPool *poolp, NSSCMSAttribute *attr, SECItem *value) { SECItem *copiedvalue; void *mark; PORT_Assert (poolp != NULL); mark = PORT_ArenaMark(poolp); if (value == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); goto loser; } if ((copiedvalue = SECITEM_ArenaDupItem(poolp, value)) == NULL) goto loser; if (NSS_CMSArray_Add(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; }
SECStatus NSS_CMSSignedData_AddDigest(PLArenaPool *poolp, NSSCMSSignedData *sigd, SECOidTag digestalgtag, SECItem *digest) { SECAlgorithmID *digestalg; void *mark; if (!sigd || !poolp) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } 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 (NSS_CMSArray_Add(poolp, (void ***)&(sigd->digestAlgorithms), (void *)digestalg) != SECSuccess || /* even if digest is NULL, add dummy to have same-size array */ NSS_CMSArray_Add(poolp, (void ***)&(sigd->digests), (void *)digest) != SECSuccess) { goto loser; } PORT_ArenaUnmark(poolp, mark); return SECSuccess; loser: PORT_ArenaRelease(poolp, mark); return SECFailure; }
SECStatus NSS_CMSSignedData_AddCertificate(NSSCMSSignedData *sigd, CERTCertificate *cert) { CERTCertificate *c; SECStatus rv; if (!sigd || !cert) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } c = CERT_DupCertificate(cert); rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->certs), (void *)c); return rv; }
SECStatus NSS_CMSSignedData_AddCertList(NSSCMSSignedData *sigd, CERTCertificateList *certlist) { SECStatus rv; if (!sigd || !certlist) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* XXX memory?? a certlist has an arena of its own and is not refcounted!?!? */ rv = NSS_CMSArray_Add(sigd->cmsg->poolp, (void ***)&(sigd->certLists), (void *)certlist); return rv; }
SECStatus NSS_CMSSignedData_AddSignerInfo(NSSCMSSignedData *sigd, NSSCMSSignerInfo *signerinfo) { void *mark; SECStatus rv; SECOidTag digestalgtag; PLArenaPool *poolp; if (!sigd || !signerinfo) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } poolp = sigd->cmsg->poolp; mark = PORT_ArenaMark(poolp); /* add signerinfo */ rv = NSS_CMSArray_Add(poolp, (void ***)&(sigd->signerInfos), (void *)signerinfo); if (rv != SECSuccess) goto loser; /* * 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 = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo); rv = NSS_CMSSignedData_SetDigestValue(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; }
/* * NSS_CMSAttribute_Create - create an attribute * * if value is NULL, the attribute won't have a value. It can be added later * with NSS_CMSAttribute_AddValue. */ NSSCMSAttribute * NSS_CMSAttribute_Create(PRArenaPool *poolp, SECOidTag oidtag, SECItem *value, PRBool encoded) { NSSCMSAttribute *attr; SECItem *copiedvalue; void *mark; PORT_Assert (poolp != NULL); mark = PORT_ArenaMark (poolp); attr = (NSSCMSAttribute *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSAttribute)); 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_ArenaDupItem(poolp, value)) == NULL) goto loser; if (NSS_CMSArray_Add(poolp, (void ***)&(attr->values), (void *)copiedvalue) != SECSuccess) goto loser; } attr->encoded = encoded; PORT_ArenaUnmark (poolp, mark); return attr; loser: PORT_Assert (mark != NULL); PORT_ArenaRelease (poolp, mark); return NULL; }
/* * NSS_CMSEnvelopedData_AddRecipient - add a recipientinfo to the enveloped data msg * * rip must be created on the same pool as edp - this is not enforced, though. */ SECStatus NSS_CMSEnvelopedData_AddRecipient(NSSCMSEnvelopedData *edp, NSSCMSRecipientInfo *rip) { void *mark; SECStatus 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 = NSS_CMSArray_Add(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; }
NSSCMSRecipientInfo * nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, NSSCMSRecipientIDSelector type, CERTCertificate *cert, SECKEYPublicKey *pubKey, SECItem *subjKeyID, void* pwfn_arg, SECItem* DERinput) { NSSCMSRecipientInfo *ri; void *mark; SECOidTag certalgtag; SECStatus rv = SECSuccess; NSSCMSRecipientEncryptedKey *rek; NSSCMSOriginatorIdentifierOrKey *oiok; unsigned long version; SECItem *dummy; PLArenaPool *poolp; CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL; NSSCMSRecipientIdentifier *rid; extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; if (!cmsg) { /* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc * and a private arena pool */ cmsg = NSS_CMSMessage_Create(NULL); cmsg->pwfn_arg = pwfn_arg; /* mark it as a special cms message */ cmsg->contentInfo.contentTypeTag = (SECOidData *)&fakeContent; } poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo)); if (ri == NULL) goto loser; ri->cmsg = cmsg; if (DERinput) { /* decode everything from DER */ SECItem newinput; SECStatus rv = SECITEM_CopyItem(poolp, &newinput, DERinput); if (SECSuccess != rv) goto loser; rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput); if (SECSuccess != rv) goto loser; } switch (type) { case NSSCMSRecipientID_IssuerSN: { ri->cert = CERT_DupCertificate(cert); if (NULL == ri->cert) goto loser; spki = &(cert->subjectPublicKeyInfo); break; } case NSSCMSRecipientID_SubjectKeyID: { PORT_Assert(pubKey); spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey); break; } case NSSCMSRecipientID_BrandNew: goto done; break; default: /* unkown type */ goto loser; break; } certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm)); rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans; rid->identifierType = type; if (type == NSSCMSRecipientID_IssuerSN) { rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); if (rid->id.issuerAndSN == NULL) { break; } } else if (type == NSSCMSRecipientID_SubjectKeyID){ NSSCMSKeyTransRecipientInfoEx *riExtra; rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem); 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; } 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; } } else { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } break; case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ PORT_Assert(type == NSSCMSRecipientID_IssuerSN); if (type != NSSCMSRecipientID_IssuerSN) { rv = SECFailure; break; } /* a key agreement op */ ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree; 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 = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) { rv = SECFailure; break; } /* hardcoded IssuerSN choice for now */ rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN; 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 = NSSCMSOriginatorIDOrKey_OriginatorPublicKey; rv = NSS_CMSArray_Add(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 NSSCMSRecipientInfoID_KeyTrans: if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN) version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN; else version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY; dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version); if (dummy == NULL) goto loser; break; case NSSCMSRecipientInfoID_KeyAgree: dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version), NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION); if (dummy == NULL) goto loser; break; case NSSCMSRecipientInfoID_KEK: /* NOTE: this cannot happen as long as we do not support any KEK algorithm */ dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version), NSS_CMS_KEK_RECIPIENT_INFO_VERSION); if (dummy == NULL) goto loser; break; } done: PORT_ArenaUnmark (poolp, mark); if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); return ri; loser: if (ri && ri->cert) { CERT_DestroyCertificate(ri->cert); } if (freeSpki) { SECKEY_DestroySubjectPublicKeyInfo(freeSpki); } PORT_ArenaRelease (poolp, mark); if (cmsg->contentInfo.contentTypeTag == &fakeContent) { NSS_CMSMessage_Destroy(cmsg); } return NULL; }