SECStatus SGN_CopyDigestInfo(PLArenaPool *poolp, SGNDigestInfo *a, SGNDigestInfo *b) { SECStatus rv; void *mark; if ((poolp == NULL) || (a == NULL) || (b == NULL)) return SECFailure; mark = PORT_ArenaMark(poolp); a->arena = poolp; rv = SECOID_CopyAlgorithmID(poolp, &a->digestAlgorithm, &b->digestAlgorithm); if (rv == SECSuccess) rv = SECITEM_CopyItem(poolp, &a->digest, &b->digest); if (rv != SECSuccess) { PORT_ArenaRelease(poolp, mark); } else { PORT_ArenaUnmark(poolp, mark); } return rv; }
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; }
/* * SecCmsDigestContextFinishMultiple - finish the digests and put them * into an array of CSSM_DATAs (allocated on poolp) */ OSStatus SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx, SecArenaPoolRef poolp, CSSM_DATA_PTR **digestsp) { CSSM_CC_HANDLE digobj; CSSM_DATA_PTR *digests, digest; int i; void *mark; OSStatus rv = SECFailure; /* no contents? do not update digests */ if (digestsp == NULL || !cmsdigcx->saw_contents) { for (i = 0; i < cmsdigcx->digcnt; i++) if (cmsdigcx->digobjs[i]) CSSM_DeleteContext(cmsdigcx->digobjs[i]); rv = SECSuccess; if (digestsp) *digestsp = NULL; goto cleanup; } mark = PORT_ArenaMark ((PLArenaPool *)poolp); /* allocate digest array & CSSM_DATAs on arena */ digests = (CSSM_DATA_PTR *)PORT_ArenaAlloc((PLArenaPool *)poolp, (cmsdigcx->digcnt+1) * sizeof(CSSM_DATA_PTR)); digest = (CSSM_DATA_PTR)PORT_ArenaZAlloc((PLArenaPool *)poolp, cmsdigcx->digcnt * sizeof(CSSM_DATA)); if (digests == NULL || digest == NULL) { goto loser; } for (i = 0; i < cmsdigcx->digcnt; i++, digest++) { digobj = cmsdigcx->digobjs[i]; CSSM_QUERY_SIZE_DATA dataSize; rv = CSSM_QuerySize(digobj, CSSM_FALSE, 1, &dataSize); if (rv != CSSM_OK) { goto loser; } int diglength = dataSize.SizeOutputBlock; if (digobj) { digest->Data = (unsigned char*)PORT_ArenaAlloc((PLArenaPool *)poolp, diglength); if (digest->Data == NULL) goto loser; digest->Length = diglength; rv = CSSM_DigestDataFinal(digobj, digest); if (rv != CSSM_OK) { goto loser; } CSSM_DeleteContext(digobj); } else { digest->Data = NULL; digest->Length = 0; } digests[i] = digest; } digests[i] = NULL; *digestsp = digests; rv = SECSuccess; loser: if (rv == SECSuccess) PORT_ArenaUnmark((PLArenaPool *)poolp, mark); else PORT_ArenaRelease((PLArenaPool *)poolp, mark); cleanup: if (cmsdigcx->digcnt > 0) { PORT_Free(cmsdigcx->digobjs); } PORT_Free(cmsdigcx); return rv; }
/* create a new external bag which is appended onto the list * of bags in baggage. the bag is created in the same arena * as baggage */ SEC_PKCS12BaggageItem * sec_pkcs12_create_external_bag(SEC_PKCS12Baggage *luggage) { void *dummy, *mark; SEC_PKCS12BaggageItem *bag; if(luggage == NULL) { return NULL; } mark = PORT_ArenaMark(luggage->poolp); /* allocate space for null terminated bag list */ if(luggage->bags == NULL) { luggage->bags=(SEC_PKCS12BaggageItem**)PORT_ArenaZAlloc(luggage->poolp, sizeof(SEC_PKCS12BaggageItem *)); if(luggage->bags == NULL) { goto loser; } luggage->luggage_size = 0; } /* grow the list */ dummy = PORT_ArenaGrow(luggage->poolp, luggage->bags, sizeof(SEC_PKCS12BaggageItem *) * (luggage->luggage_size + 1), sizeof(SEC_PKCS12BaggageItem *) * (luggage->luggage_size + 2)); if(dummy == NULL) { goto loser; } luggage->bags = (SEC_PKCS12BaggageItem**)dummy; luggage->bags[luggage->luggage_size] = (SEC_PKCS12BaggageItem *)PORT_ArenaZAlloc(luggage->poolp, sizeof(SEC_PKCS12BaggageItem)); if(luggage->bags[luggage->luggage_size] == NULL) { goto loser; } /* create new bag and append it to the end */ bag = luggage->bags[luggage->luggage_size]; bag->espvks = (SEC_PKCS12ESPVKItem **)PORT_ArenaZAlloc( luggage->poolp, sizeof(SEC_PKCS12ESPVKItem *)); bag->unencSecrets = (SEC_PKCS12SafeBag **)PORT_ArenaZAlloc( luggage->poolp, sizeof(SEC_PKCS12SafeBag *)); if((bag->espvks == NULL) || (bag->unencSecrets == NULL)) { goto loser; } bag->poolp = luggage->poolp; luggage->luggage_size++; luggage->bags[luggage->luggage_size] = NULL; bag->espvks[0] = NULL; bag->unencSecrets[0] = NULL; bag->nEspvks = bag->nSecrets = 0; PORT_ArenaUnmark(luggage->poolp, mark); return bag; loser: PORT_ArenaRelease(luggage->poolp, mark); PORT_SetError(SEC_ERROR_NO_MEMORY); return NULL; }
/* * NSS_CMSEnvelopedData_Encode_BeforeStart - 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. */ SECStatus NSS_CMSEnvelopedData_Encode_BeforeStart(NSSCMSEnvelopedData *envd) { int version; NSSCMSRecipientInfo **recipientinfos; NSSCMSContentInfo *cinfo; PK11SymKey *bulkkey = NULL; SECOidTag bulkalgtag; CK_MECHANISM_TYPE type; PK11SlotInfo *slot; SECStatus rv; SECItem *dummy; PLArenaPool *poolp; extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; 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 = NSS_CMS_ENVELOPED_DATA_VERSION_REG; if (envd->originatorInfo != NULL || envd->unprotectedAttr != NULL) { version = NSS_CMS_ENVELOPED_DATA_VERSION_ADV; } else { for (i = 0; recipientinfos[i] != NULL; i++) { if (NSS_CMSRecipientInfo_GetVersion(recipientinfos[i]) != 0) { version = NSS_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 = NSS_CMSContentInfo_GetContentEncAlgTag(cinfo)) == SEC_OID_UNKNOWN) { rv = NSS_CMSContentInfo_SetContentEncAlg(poolp, cinfo, SEC_OID_DES_EDE3_CBC, NULL, 168); if (rv != SECSuccess) goto loser; bulkalgtag = SEC_OID_DES_EDE3_CBC; } /* generate a random bulk key suitable for content encryption alg */ type = PK11_AlgtagToMechanism(bulkalgtag); slot = PK11_GetBestSlot(type, envd->cmsg->pwfn_arg); if (slot == NULL) goto loser; /* error has been set by PK11_GetBestSlot */ /* this is expensive... */ bulkkey = PK11_KeyGen(slot, type, NULL, NSS_CMSContentInfo_GetBulkKeySize(cinfo) / 8, envd->cmsg->pwfn_arg); PK11_FreeSlot(slot); if (bulkkey == NULL) goto loser; /* error has been set by PK11_KeyGen */ mark = PORT_ArenaMark(poolp); /* Encrypt the bulk key with the public key of each recipient. */ for (i = 0; recipientinfos[i] != NULL; i++) { rv = NSS_CMSRecipientInfo_WrapBulkKey(recipientinfos[i], bulkkey, bulkalgtag); if (rv != SECSuccess) goto loser; /* error has been set by NSS_CMSRecipientInfo_EncryptBulkKey */ /* could be: alg not supported etc. */ } /* the recipientinfos are all finished. now sort them by DER for SET OF encoding */ rv = NSS_CMSArray_SortByDER((void **)envd->recipientInfos, NSSCMSRecipientInfoTemplate, NULL); if (rv != SECSuccess) goto loser; /* error has been set by NSS_CMSArray_SortByDER */ /* store the bulk key in the contentInfo so that the encoder can find it */ NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey); PORT_ArenaUnmark(poolp, mark); PK11_FreeSymKey(bulkkey); return SECSuccess; loser: if (mark != NULL) PORT_ArenaRelease (poolp, mark); if (bulkkey) PK11_FreeSymKey(bulkkey); return SECFailure; }
/* * check to see if the module has added new slots. PKCS 11 v2.20 allows for * modules to add new slots, but never remove them. Slots cannot be added * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently * grow on the caller. It is permissible for the slots to increase between * successive calls with NULL to get the size. */ SECStatus SECMOD_UpdateSlotList(SECMODModule *mod) { CK_RV crv; CK_ULONG count; CK_ULONG i, oldCount; PRBool freeRef = PR_FALSE; void *mark = NULL; CK_ULONG *slotIDs = NULL; PK11SlotInfo **newSlots = NULL; PK11SlotInfo **oldSlots = NULL; if (!moduleLock) { PORT_SetError(SEC_ERROR_NOT_INITIALIZED); return SECFailure; } /* C_GetSlotList is not a session function, make sure * calls are serialized */ PZ_Lock(mod->refLock); freeRef = PR_TRUE; /* see if the number of slots have changed */ crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); goto loser; } /* nothing new, blow out early, we want this function to be quick * and cheap in the normal case */ if (count == mod->slotCount) { PZ_Unlock(mod->refLock); return SECSuccess; } if (count < (CK_ULONG)mod->slotCount) { /* shouldn't happen with a properly functioning PKCS #11 module */ PORT_SetError( SEC_ERROR_INCOMPATIBLE_PKCS11 ); goto loser; } /* get the new slot list */ slotIDs = PORT_NewArray(CK_SLOT_ID, count); if (slotIDs == NULL) { goto loser; } crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count); if (crv != CKR_OK) { PORT_SetError(PK11_MapError(crv)); goto loser; } freeRef = PR_FALSE; PZ_Unlock(mod->refLock); mark = PORT_ArenaMark(mod->arena); if (mark == NULL) { goto loser; } newSlots = PORT_ArenaZNewArray(mod->arena,PK11SlotInfo *,count); /* walk down the new slot ID list returned from the module. We keep * the old slots which match a returned ID, and we initialize the new * slots. */ for (i=0; i < count; i++) { PK11SlotInfo *slot = SECMOD_FindSlotByID(mod,slotIDs[i]); if (!slot) { /* we have a new slot create a new slot data structure */ slot = PK11_NewSlotInfo(mod); if (!slot) { goto loser; } PK11_InitSlot(mod, slotIDs[i], slot); STAN_InitTokenForSlotInfo(NULL, slot); } newSlots[i] = slot; } STAN_ResetTokenInterator(NULL); PORT_Free(slotIDs); slotIDs = NULL; PORT_ArenaUnmark(mod->arena, mark); /* until this point we're still using the old slot list. Now we update * module slot list. We update the slots (array) first then the count, * since we've already guarrenteed that count has increased (just in case * someone is looking at the slots field of module without holding the * moduleLock */ SECMOD_GetWriteLock(moduleLock); oldCount =mod->slotCount; oldSlots = mod->slots; mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is * allocated out of the module arena and won't * be freed until the module is freed */ mod->slotCount = count; SECMOD_ReleaseWriteLock(moduleLock); /* free our old references before forgetting about oldSlot*/ for (i=0; i < oldCount; i++) { PK11_FreeSlot(oldSlots[i]); } return SECSuccess; loser: if (freeRef) { PZ_Unlock(mod->refLock); } if (slotIDs) { PORT_Free(slotIDs); } /* free all the slots we allocated. newSlots are part of the * mod arena. NOTE: the newSlots array contain both new and old * slots, but we kept a reference to the old slots when we built the new * array, so we need to free all the slots in newSlots array. */ if (newSlots) { for (i=0; i < count; i++) { if (newSlots[i] == NULL) { break; /* hit the last one */ } PK11_FreeSlot(newSlots[i]); } } /* must come after freeing newSlots */ if (mark) { PORT_ArenaRelease(mod->arena, mark); } return SECFailure; }
// Extract the issuer and serial number from a certificate SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert) { OSStatus status; SecCmsIssuerAndSN *certIssuerAndSN; CSSM_CL_HANDLE clHandle; CSSM_DATA_PTR serialNumber = 0; CSSM_DATA_PTR issuer = 0; CSSM_DATA certData = {}; CSSM_HANDLE resultsHandle = 0; uint32 numberOfFields = 0; CSSM_RETURN result; void *mark; mark = PORT_ArenaMark(pl); status = SecCertificateGetCLHandle(cert, &clHandle); if (status) goto loser; status = SecCertificateGetData(cert, &certData); if (status) goto loser; /* Get the issuer from the cert. */ result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData, &OID_X509V1IssuerNameStd, &resultsHandle, &numberOfFields, &issuer); if (result || numberOfFields < 1) goto loser; result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle); if (result) goto loser; /* Get the serialNumber from the cert. */ result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData, &CSSMOID_X509V1SerialNumber, &resultsHandle, &numberOfFields, &serialNumber); if (result || numberOfFields < 1) goto loser; result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle); if (result) goto loser; /* Allocate the SecCmsIssuerAndSN struct. */ certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN)); if (certIssuerAndSN == NULL) goto loser; /* Copy the issuer. */ certIssuerAndSN->derIssuer.Data = (uint8 *) PORT_ArenaAlloc(pl, issuer->Length); if (!certIssuerAndSN->derIssuer.Data) goto loser; PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer->Data, issuer->Length); certIssuerAndSN->derIssuer.Length = issuer->Length; /* Copy the serialNumber. */ certIssuerAndSN->serialNumber.Data = (uint8 *) PORT_ArenaAlloc(pl, serialNumber->Length); if (!certIssuerAndSN->serialNumber.Data) goto loser; PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber->Data, serialNumber->Length); certIssuerAndSN->serialNumber.Length = serialNumber->Length; PORT_ArenaUnmark(pl, mark); CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber); CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer); return certIssuerAndSN; loser: PORT_ArenaRelease(pl, mark); if (serialNumber) CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber); if (issuer) CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer); PORT_SetError(SEC_INTERNAL_ONLY); return NULL; }
static sec_PKCS7CipherObject * sec_pkcs7_encoder_start_encrypt (SEC_PKCS7ContentInfo *cinfo, PK11SymKey *orig_bulkkey) { SECOidTag kind; sec_PKCS7CipherObject *encryptobj; SEC_PKCS7RecipientInfo **recipientinfos, *ri; SEC_PKCS7EncryptedContentInfo *enccinfo; SECKEYPublicKey *publickey = NULL; SECKEYPrivateKey *ourPrivKey = NULL; PK11SymKey *bulkkey; void *mark, *wincx; int i; PLArenaPool *arena = NULL; /* Get the context in case we need it below. */ wincx = cinfo->pwfn_arg; kind = SEC_PKCS7ContentType (cinfo); switch (kind) { default: case SEC_OID_PKCS7_DATA: case SEC_OID_PKCS7_DIGESTED_DATA: case SEC_OID_PKCS7_SIGNED_DATA: recipientinfos = NULL; enccinfo = NULL; break; case SEC_OID_PKCS7_ENCRYPTED_DATA: { SEC_PKCS7EncryptedData *encdp; /* To do EncryptedData we *must* be given a bulk key. */ PORT_Assert (orig_bulkkey != NULL); if (orig_bulkkey == NULL) { /* XXX error? */ return NULL; } encdp = cinfo->content.encryptedData; recipientinfos = NULL; enccinfo = &(encdp->encContentInfo); } break; case SEC_OID_PKCS7_ENVELOPED_DATA: { SEC_PKCS7EnvelopedData *envdp; envdp = cinfo->content.envelopedData; recipientinfos = envdp->recipientInfos; enccinfo = &(envdp->encContentInfo); } break; case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: { SEC_PKCS7SignedAndEnvelopedData *saedp; saedp = cinfo->content.signedAndEnvelopedData; recipientinfos = saedp->recipientInfos; enccinfo = &(saedp->encContentInfo); } break; } if (enccinfo == NULL) return NULL; bulkkey = orig_bulkkey; if (bulkkey == NULL) { CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(enccinfo->encalg); PK11SlotInfo *slot; slot = PK11_GetBestSlot(type,cinfo->pwfn_arg); if (slot == NULL) { return NULL; } bulkkey = PK11_KeyGen(slot,type,NULL, enccinfo->keysize/8, cinfo->pwfn_arg); PK11_FreeSlot(slot); if (bulkkey == NULL) { return NULL; } } encryptobj = NULL; mark = PORT_ArenaMark (cinfo->poolp); /* * Encrypt the bulk key with the public key of each recipient. */ for (i = 0; recipientinfos && (ri = recipientinfos[i]) != NULL; i++) { CERTCertificate *cert; SECOidTag certalgtag, encalgtag; SECStatus rv; int data_len; SECItem *params = NULL; cert = ri->cert; PORT_Assert (cert != NULL); if (cert == NULL) continue; /* * XXX Want an interface that takes a cert and some data and * fills in an algorithmID and encrypts the data with the public * key from the cert. Or, give me two interfaces -- one which * gets the algorithm tag from a cert (I should not have to go * down into the subjectPublicKeyInfo myself) and another which * takes a public key and algorithm tag and data and encrypts * the data. Or something like that. The point is that all * of the following hardwired RSA stuff should be done elsewhere. */ certalgtag=SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); switch (certalgtag) { case SEC_OID_PKCS1_RSA_ENCRYPTION: encalgtag = certalgtag; publickey = CERT_ExtractPublicKey (cert); if (publickey == NULL) goto loser; data_len = SECKEY_PublicKeyStrength(publickey); ri->encKey.data = (unsigned char*)PORT_ArenaAlloc(cinfo->poolp ,data_len); ri->encKey.len = data_len; if (ri->encKey.data == NULL) goto loser; rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(certalgtag),publickey, bulkkey,&ri->encKey); SECKEY_DestroyPublicKey(publickey); publickey = NULL; if (rv != SECSuccess) goto loser; params = NULL; /* paranoia */ break; default: PORT_SetError (SEC_ERROR_INVALID_ALGORITHM); goto loser; } rv = SECOID_SetAlgorithmID(cinfo->poolp, &ri->keyEncAlg, encalgtag, params); if (rv != SECSuccess) goto loser; if (arena) PORT_FreeArena(arena,PR_FALSE); arena = NULL; } encryptobj = sec_PKCS7CreateEncryptObject (cinfo->poolp, bulkkey, enccinfo->encalg, &(enccinfo->contentEncAlg)); if (encryptobj != NULL) { PORT_ArenaUnmark (cinfo->poolp, mark); mark = NULL; /* good one; do not want to release */ } /* fallthru */ loser: if (arena) { PORT_FreeArena(arena, PR_FALSE); } if (publickey) { SECKEY_DestroyPublicKey(publickey); } if (ourPrivKey) { SECKEY_DestroyPrivateKey(ourPrivKey); } if (mark != NULL) { PORT_ArenaRelease (cinfo->poolp, mark); } if (orig_bulkkey == NULL) { if (bulkkey) PK11_FreeSymKey(bulkkey); } return encryptobj; }
/* the content of an encrypted data content info is encrypted. * it is assumed that for encrypted data, that the data has already * been set and is in the "plainContent" field of the content info. * * cinfo is the content info to encrypt * * key is the key with which to perform the encryption. if the * algorithm is a password based encryption algorithm, the * key is actually a password which will be processed per * PKCS #5. * * in the event of an error, SECFailure is returned. SECSuccess * indicates a success. */ SECStatus SEC_PKCS7EncryptContents(PRArenaPool *poolp, SEC_PKCS7ContentInfo *cinfo, SECItem *key, void *wincx) { SECAlgorithmID *algid = NULL; SECItem * result = NULL; SECItem * src; SECItem * dest; SECItem * blocked_data = NULL; void * mark; void * cx; PK11SymKey * eKey = NULL; PK11SlotInfo * slot = NULL; CK_MECHANISM_TYPE cryptoMechType; int bs; SECStatus rv = SECFailure; SECItem *c_param = NULL; if((cinfo == NULL) || (key == NULL)) return SECFailure; if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA) return SECFailure; algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo); if(algid == NULL) return SECFailure; if(poolp == NULL) poolp = cinfo->poolp; mark = PORT_ArenaMark(poolp); src = &cinfo->content.encryptedData->encContentInfo.plainContent; dest = &cinfo->content.encryptedData->encContentInfo.encContent; dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64)); dest->len = (src->len + 64); if(dest->data == NULL) { rv = SECFailure; goto loser; } slot = PK11_GetInternalKeySlot(); if(slot == NULL) { rv = SECFailure; goto loser; } eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx); if(eKey == NULL) { rv = SECFailure; goto loser; } cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key); if (cryptoMechType == CKM_INVALID_MECHANISM) { rv = SECFailure; goto loser; } /* block according to PKCS 8 */ bs = PK11_GetBlockSize(cryptoMechType, c_param); rv = SECSuccess; if(bs) { char pad_char; pad_char = (char)(bs - (src->len % bs)); if(src->len % bs) { rv = SECSuccess; blocked_data = PK11_BlockData(src, bs); if(blocked_data) { PORT_Memset((blocked_data->data + blocked_data->len - (int)pad_char), pad_char, (int)pad_char); } else { rv = SECFailure; goto loser; } } else { blocked_data = SECITEM_DupItem(src); if(blocked_data) { blocked_data->data = (unsigned char*)PORT_Realloc( blocked_data->data, blocked_data->len + bs); if(blocked_data->data) { blocked_data->len += bs; PORT_Memset((blocked_data->data + src->len), (char)bs, bs); } else { rv = SECFailure; goto loser; } } else { rv = SECFailure; goto loser; } } } else { blocked_data = SECITEM_DupItem(src); if(!blocked_data) { rv = SECFailure; goto loser; } } cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_ENCRYPT, eKey, c_param); if(cx == NULL) { rv = SECFailure; goto loser; } rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len), (int)(src->len + 64), blocked_data->data, (int)blocked_data->len); PK11_DestroyContext((PK11Context*)cx, PR_TRUE); loser: /* let success fall through */ if(blocked_data != NULL) SECITEM_ZfreeItem(blocked_data, PR_TRUE); if(result != NULL) SECITEM_ZfreeItem(result, PR_TRUE); if(rv == SECFailure) PORT_ArenaRelease(poolp, mark); else PORT_ArenaUnmark(poolp, mark); if(eKey != NULL) PK11_FreeSymKey(eKey); if(slot != NULL) PK11_FreeSlot(slot); if(c_param != NULL) SECITEM_ZfreeItem(c_param, PR_TRUE); return rv; }
NSSCMSSignerInfo * nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type, CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey, SECKEYPrivateKey *signingKey, SECOidTag digestalgtag) { void *mark; NSSCMSSignerInfo *signerinfo; int version; PLArenaPool *poolp; poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo)); if (signerinfo == NULL) { PORT_ArenaRelease(poolp, mark); return NULL; } signerinfo->cmsg = cmsg; switch(type) { case NSSCMSSignerID_IssuerSN: signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_IssuerSN; if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL) goto loser; if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) goto loser; break; case NSSCMSSignerID_SubjectKeyID: signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_SubjectKeyID; PORT_Assert(subjKeyID); if (!subjKeyID) goto loser; signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, SECItem); SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID, subjKeyID); signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey); if (!signerinfo->signingKey) goto loser; signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey); if (!signerinfo->pubKey) goto loser; break; default: goto loser; } /* set version right now */ version = NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN; /* RFC2630 5.3 "version is the syntax version number. If the .... " */ if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID) version = NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY; (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version); if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return signerinfo; loser: PORT_ArenaRelease(poolp, mark); return NULL; }
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; }
SECItemArray * SECITEM_AllocArray(PLArenaPool *arena, SECItemArray *array, unsigned int len) { SECItemArray *result = NULL; void *mark = NULL; if (arena != NULL) { mark = PORT_ArenaMark(arena); } if (array == NULL) { if (arena != NULL) { result = PORT_ArenaZAlloc(arena, sizeof(SECItemArray)); } else { result = PORT_ZAlloc(sizeof(SECItemArray)); } if (result == NULL) { goto loser; } } else { PORT_Assert(array->items == NULL); result = array; } result->len = len; if (len) { if (arena != NULL) { result->items = PORT_ArenaZNewArray(arena, SECItem, len); } else { result->items = PORT_ZNewArray(SECItem, len); } if (result->items == NULL) { goto loser; } } else { result->items = NULL; } if (mark) { PORT_ArenaUnmark(arena, mark); } return(result); loser: if ( arena != NULL ) { if (mark) { PORT_ArenaRelease(arena, mark); } if (array != NULL) { array->items = NULL; array->len = 0; } } else { if (result != NULL && array == NULL) { PORT_Free(result); } /* * If array is not NULL, the above has set array->data and * array->len to 0. */ } 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; }
SecCmsSignerInfoRef nss_cmssignerinfo_create(SecCmsMessageRef cmsg, SecCmsSignerIDSelector type, SecCertificateRef cert, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag) { void *mark; SecCmsSignerInfoRef signerinfo; int version; PLArenaPool *poolp; poolp = cmsg->poolp; mark = PORT_ArenaMark(poolp); signerinfo = (SecCmsSignerInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsSignerInfo)); if (signerinfo == NULL) { PORT_ArenaRelease(poolp, mark); return NULL; } signerinfo->cmsg = cmsg; switch(type) { case SecCmsSignerIDIssuerSN: signerinfo->signerIdentifier.identifierType = SecCmsSignerIDIssuerSN; if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL) goto loser; if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) goto loser; dprintfRC("nss_cmssignerinfo_create: SecCmsSignerIDIssuerSN: cert.rc %d\n", (int)CFGetRetainCount(signerinfo->cert)); break; case SecCmsSignerIDSubjectKeyID: signerinfo->signerIdentifier.identifierType = SecCmsSignerIDSubjectKeyID; PORT_Assert(subjKeyID); if (!subjKeyID) goto loser; signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, CSSM_DATA); if (SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID, subjKeyID)) { goto loser; } signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey); if (!signerinfo->pubKey) goto loser; break; default: goto loser; } if (!signingKey) goto loser; signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey); if (!signerinfo->signingKey) goto loser; /* set version right now */ version = SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN; /* RFC2630 5.3 "version is the syntax version number. If the .... " */ if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID) version = SEC_CMS_SIGNER_INFO_VERSION_SUBJKEY; (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version); if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess) goto loser; PORT_ArenaUnmark(poolp, mark); return signerinfo; loser: PORT_ArenaRelease(poolp, mark); return NULL; }
SECItem * SECITEM_AllocItem(PLArenaPool *arena, SECItem *item, unsigned int len) { SECItem *result = NULL; void *mark = NULL; if (arena != NULL) { mark = PORT_ArenaMark(arena); } if (item == NULL) { if (arena != NULL) { result = PORT_ArenaZAlloc(arena, sizeof(SECItem)); } else { result = PORT_ZAlloc(sizeof(SECItem)); } if (result == NULL) { goto loser; } } else { PORT_Assert(item->data == NULL); result = item; } result->len = len; if (len) { if (arena != NULL) { result->data = PORT_ArenaAlloc(arena, len); } else { result->data = PORT_Alloc(len); } if (result->data == NULL) { goto loser; } } else { result->data = NULL; } if (mark) { PORT_ArenaUnmark(arena, mark); } return(result); loser: if ( arena != NULL ) { if (mark) { PORT_ArenaRelease(arena, mark); } if (item != NULL) { item->data = NULL; item->len = 0; } } else { if (result != NULL) { SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE); } /* * If item is not NULL, the above has set item->data and * item->len to 0. */ } return(NULL); }
SECItemArray * SECITEM_AllocArray(PLArenaPool *arena, SECItemArray *array, unsigned int len) { SECItemArray *result = NULL; void *mark = NULL; if (array != NULL && array->items != NULL) { PORT_Assert(0); PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } if (arena != NULL) { mark = PORT_ArenaMark(arena); } if (array == NULL) { if (arena != NULL) { result = PORT_ArenaZAlloc(arena, sizeof(SECItemArray)); } else { result = PORT_ZAlloc(sizeof(SECItemArray)); } if (result == NULL) { goto loser; } } else { result = array; } result->len = len; if (len) { if (arena != NULL) { result->items = PORT_ArenaZNewArray(arena, SECItem, len); } else { result->items = PORT_ZNewArray(SECItem, len); } if (result->items == NULL) { goto loser; } } else { result->items = NULL; } if (mark) { PORT_ArenaUnmark(arena, mark); } return result; loser: if ( arena != NULL ) { if (mark) { PORT_ArenaRelease(arena, mark); } } else { if (result != NULL && array == NULL) { PORT_Free(result); } } if (array != NULL) { array->items = NULL; array->len = 0; } return NULL; }
/* the content of an encrypted data content info is decrypted. * it is assumed that for encrypted data, that the data has already * been set and is in the "encContent" field of the content info. * * cinfo is the content info to decrypt * * key is the key with which to perform the decryption. if the * algorithm is a password based encryption algorithm, the * key is actually a password which will be processed per * PKCS #5. * * in the event of an error, SECFailure is returned. SECSuccess * indicates a success. */ SECStatus SEC_PKCS7DecryptContents(PRArenaPool *poolp, SEC_PKCS7ContentInfo *cinfo, SECItem *key, void *wincx) { SECAlgorithmID *algid = NULL; SECStatus rv = SECFailure; SECItem *result = NULL, *dest, *src; void *mark; PK11SymKey *eKey = NULL; PK11SlotInfo *slot = NULL; CK_MECHANISM_TYPE cryptoMechType; void *cx; SECItem *c_param = NULL; int bs; if((cinfo == NULL) || (key == NULL)) return SECFailure; if(SEC_PKCS7ContentType(cinfo) != SEC_OID_PKCS7_ENCRYPTED_DATA) return SECFailure; algid = SEC_PKCS7GetEncryptionAlgorithm(cinfo); if(algid == NULL) return SECFailure; if(poolp == NULL) poolp = cinfo->poolp; mark = PORT_ArenaMark(poolp); src = &cinfo->content.encryptedData->encContentInfo.encContent; dest = &cinfo->content.encryptedData->encContentInfo.plainContent; dest->data = (unsigned char*)PORT_ArenaZAlloc(poolp, (src->len + 64)); dest->len = (src->len + 64); if(dest->data == NULL) { rv = SECFailure; goto loser; } slot = PK11_GetInternalKeySlot(); if(slot == NULL) { rv = SECFailure; goto loser; } eKey = PK11_PBEKeyGen(slot, algid, key, PR_FALSE, wincx); if(eKey == NULL) { rv = SECFailure; goto loser; } cryptoMechType = PK11_GetPBECryptoMechanism(algid, &c_param, key); if (cryptoMechType == CKM_INVALID_MECHANISM) { rv = SECFailure; goto loser; } cx = PK11_CreateContextBySymKey(cryptoMechType, CKA_DECRYPT, eKey, c_param); if(cx == NULL) { rv = SECFailure; goto loser; } rv = PK11_CipherOp((PK11Context*)cx, dest->data, (int *)(&dest->len), (int)(src->len + 64), src->data, (int)src->len); PK11_DestroyContext((PK11Context *)cx, PR_TRUE); bs = PK11_GetBlockSize(cryptoMechType, c_param); if(bs) { /* check for proper badding in block algorithms. this assumes * RC2 cbc or a DES cbc variant. and the padding is thus defined */ if(((int)dest->data[dest->len-1] <= bs) && ((int)dest->data[dest->len-1] > 0)) { dest->len -= (int)dest->data[dest->len-1]; } else { rv = SECFailure; /* set an error ? */ } } loser: /* let success fall through */ if(result != NULL) SECITEM_ZfreeItem(result, PR_TRUE); if(rv == SECFailure) PORT_ArenaRelease(poolp, mark); else PORT_ArenaUnmark(poolp, mark); if(eKey != NULL) PK11_FreeSymKey(eKey); if(slot != NULL) PK11_FreeSlot(slot); if(c_param != NULL) SECITEM_ZfreeItem(c_param, PR_TRUE); return rv; }